Allow a function call's argument to refer to other arguments by parameter name


#1

Consider a function of signature

fun doSmth(param1: A, param2: B)

where A and B are comcrete types, and A has a getSomeB() method, and A’s constructor performing some expensive computations. I’d like to use the function like this:

doSmth(A(), param1.GetSomeB)

More interestingly, I’d like that, when a function takes a lsmbda as a the last parameter, I can access the pther srguments of the function inside the body of the lambda.

myFunc(a=SomeObject()){ doSomethingWith(a) }

To achieve the same functionality, I need to save the fiest parameter as a value/variable before the function call. I’d like to be able to do it without that, since I may not need those values to outlive the function call, and for code terseness.


#2

This reminds me of using val in when expressions (which I really like)

What about this syntax instead:

// Example functions (same as OP)
fun doSmth(param1: A, param2: B)
fun myFunc(a: Int, block: () -> Unit) { /* ... */ }

// "param1" is declared and used the parentheses
doSmth(val param1 = A(), param1.GetSomeB)

// "a" is declared and used the parentheses and trailing closure
myFunc(val a = SomeObject()) {
  // a is in scope here.
}

IMO this would communicate the declaration of a named variable more clearly, and explicitly show the reader that a is intended to be used as a variable.


#3

I don’t know how common would be this use case.

@arocnies, interesting usage of keyword val. It never used so far at the call-site.

Should we also expect to be able to use var at call-site? What would it mean? May be another way to return values, as a side effect.

How about:

(existingValue ?: A()).let {
    doSmth(it, it.GetSomeB)
}

Same trick for closure:

(existingValue ?: SomeObject()).let {
    myFunc(it) { a: SomeObject -> 
        // a is in scope here.
    }
}

and while myFunc(...) executes the closure it passes it as a parameter.


#4

Thanks for the tip. Hiwever, wrapping the functionality in :? + apply (plus having to declare a as a lambda argument) smell like boilerplste to me, the kind of boilerplste Kotlin strives to reduce, thus the proposal.

Using val keyword would be fine, albeit a bot redundant still, since function arguments are essentially implicits vals already. And that’s wht var would’t be expected(/legal there.

@arocnies can we already use when(val x = sth) {} ? Or is it just another proposal?


#5

This argument getting close to “religious war” if to count ?: a boilerplate code or not. I am not going there.

Just want to point that in terms of amount of code both mine and proposed looks very close in size.

However my main point was that it seams very niche use case applicable only if you have default value of the parameter, which calculated at the time of call AND used to provide values for multiple purposes. This smells bed design to me.

Please provide the real-life example where you need this to find other options.


#6

İt is being added in one of the next releases, afaik.


#7

It should be part of 1.3. It might even be part of the EAP build 1.3-M2, but I’m not sure there.


#8

Where I can read about this syntax?


#9

I guess it might also be mentioned in some block posts about kotlin 1.3 but this is the main document about it.