Shorthand lambda argument implicit names proposal


#1

Hi,

I have a proposal regarding implicit names of lambda parameters. Currently the documentation states

One other helpful convention is that if a function literal has only one parameter, its declaration may be omitted (along with the ->), and its name will be it

Here are the disadvantages of it implicit name I see:

  • Its usage can be sometimes confusing. Consider the following contrived example

      data class SomeModel(val data: List<Int>)
    
      listOf(SomeModel(data = listOf(1,2,3)), SomeModel(data = listOf(5,6,7,8)))
      .forEach { 
          // forEach `it`
          print(it)
          
          it.data.reduce { 
              // It may seem that the following `it` represetns the first reduce arg
              // But it's still the same `it` from forEach!
              a, b -> a + b + it.data.first()
          }
      }
    
  • It’s too restrictive. Why there is implicit name only for a single parameter?

I think, Kotlin could overcome these disadvantages by implementing Shorthand Argument Names the same way as in Swift programming language.

Here are the specs.

Quick Overview:

  • Instead of it name it’s better to use numeric shorthand argument names which refer to the values of the lambda’s arguments like this: $0, $1, $2, and so on.

  • To prevent ambiguity the usage of these names should be restricted to the enclosing lambda. For example, $0 in nested scope must not refer to the argument from the outer scope.

  • With shorthand argument names the previous example can be rewritten as

      data class SomeModel(val data: List<Int>)
    
      listOf(SomeModel(data = listOf(1,2,3)), SomeModel(data = listOf(5,6,7,8)))
     
      .forEach { 
    
          $0.data.reduce { 
             // Now there is no ambiguity
             // $0 refers to the argument value of the first reduce parameter
             // $0 cannot refer to the first argument of forEach
             // Note: if reduce hadn't parameters at all the usage of $0 should give a compile time error
              $0 + $1
          }
      }
    

Hope this all makes sense.


#2

Quick observation: one can use $0 inside a nested for loop, but can’t use it inside a nested lambda. This will be confusing for the user, since our lambdas are so syntactically close to blocks.