Kotlin internal and external parameter name propose

I just found this and I want to bump it for another round of consideration. This could be very useful for self-documenting, readable API code. For instance, here’s a (very stripped-out) API I’m working on that could benefit from this feature. It’s a Kotlin module for abstracting network requests which uses Retrofit and RxJava.

The API public definitions:

interface Repo {
    fun startRequest(query: String,
                     successAction: () -> Unit,
                     failureAction: (Throwable) -> Unit,
                     observeOn: Scheduler) /* <-- Okay so far... */
}

The client code could look something like this:

val repo = Repo()
repo.startRequest(
        query = "Foo",
        successAction = { /* ... */ },
        failureAction = { throwable -> /* ... */ },
        observeOn = Schedulers.computation() /* <-- Very clear what this does */
)

But the Internal implementation of the public API is a little awkward:

internal class DefaultRepo : Repo {
    override fun startRequest(query: String,
                              successAction: () -> Unit,
                              failureAction: (Throwable) -> Unit,
                              observeOn: Scheduler) {

        val disposable = retrofitApi.fooRequest(query = query)
                .observeOn(observeOn) /* <-- Awkward */
                .doOnSuccess(successAction)
                .doOnError(failureAction)
                .subscribe()
    }
}

In the above example observeOn = Schedulers.compuation() is very clear, but observeOn(observeOn) is awkward. One way to get around this is is to rename the parameter:

Public API:

interface Repo {
    fun startRequest(query: String,
                     successAction: () -> Unit,
                     failureAction: (Throwable) -> Unit,
                     scheduler: Scheduler) /* <-- Renamed from 'observeOn' */
}

Now the internal implementation looks like this:

internal class DefaultRepo : Repo {
    override fun startRequest(query: String,
                              successAction: () -> Unit,
                              failureAction: (Throwable) -> Unit,
                              scheduler: Scheduler) {

        val disposable = retrofitApi.fooRequest(query = query)
                .observeOn(scheduler) /* <-- Much cleaner, but... */
                .doOnSuccess(successAction)
                .doOnError(failureAction)
                .subscribe()
    }
}

But the client code now looks like this:

val repo = Repo()
repo.startRequest(
        query = "Foo",
        successAction = { /* ... */ },
        failureAction = { throwable -> /* ... */ },
        scheduler = Schedulers.computation() /* <-- Not clear what this does */
)

To get the best of both worlds, parameter labels could be used to make everything very clear:

Public API:

interface Repo {
    fun startRequest(query: String,
                     successAction: () -> Unit,
                     failureAction: (Throwable) -> Unit
                     observeOn scheduler: Scheduler) /* <label> <parameterName>: <Type> */
}

Internal Implementation:

internal class DefaultRepo : Repo {
    override fun startRequest(query: String,
                              successAction: () -> Unit,
                              failureAction: (Throwable) -> Unit,
                              observeOn scheduler: Scheduler) {

        val disposable = retrofitApi.fooRequest(query = query)
                .observeOn(scheduler) /* Use parameter name internally */
                .doOnSuccess(successAction)
                .doOnError(failureAction)
                .subscribe()
    }
}

And finally, client code:

val repo = Repo()
repo.startRequest(
        query = "Foo",
        successAction = { /* ... */ },
        failureAction = { throwable -> /* ... */ },
        observeOn = Schedulers.computation() /* <-- Very clear API */
)

This outlines a very simple example of the benefit to adding support for parameter labels like in Swift :rocket: I recognize that language design is very complex, so please give feedback as to whether this idea is solid :slightly_smiling_face:

7 Likes