"Receivers" for (non-lambda) function arguments


#1

I’m sorry if this was already considered and dropped, my cursory search didn’t turn up anything.
I was wondering if adding the option to specify “Receivers” to normal arguments and not only lambdas would be possible and desirable.

For example (syntax with “[Receiver]” is pseudo-code):

class Bar(val x: Int) {
    fun foo([this] y: Int) = y + 1
}
...
Bar(8).foo(x / 2) // returns 5

The interpretation would be "execute x / 2 with an additional implicit this which is the Bar object that the function was called on.

It would be loosely equivalent to:

fun foo(f: Bar.() -> Int) = this.f() + 1
...
Bar(8).foo { x / 2 }

One case where I thought it might be useful to have is for operator [] on collections.
For example:

operator fun String.get([this] index: Int) = underlyingCharArray[index]

This would allow:

val s = "Hello World"
assert(s[length - 1] == 'd') // length can be used because index has "this" as receiver

The semantic can be thought of as:

s[s.run { length - 1 }]

A different use case is with enums (this is not 100% the same but can share the same syntax):

enum class ProtocolState { WAITING, TALKING }
fun gotoState([ProtocolState] nextState: ProtocolState) = ...
...
gotoState(ProtocolState.TALKING) // this is currently required
gotoState(TALKING) // this would be possible without polluting any unwanted namespace

This proposal is more or less an extension of the “Receiver”-syntax for lambdas, just for general function arguments. It would remove quite some superfluous code (I think especially the enum cases are handy) and has strong applications for DSLs. Lambdas can already handle this fine, so I hope that arguments should be fine as well.

Note: I don’t think the [Receiver] syntax is a good choice, I just chose something unambiguous for demonstration.