Allow any name in single parameter lambda functions

It would be nice if you could choose a parameter name to your liking for simplified anonymous functions.

Example:

Before:

listOf("Bob","Eva","Zoe").map { it.toUpperCase() }

After:

listOf("Bob","Eva","Zoe").map { name.toUpperCase) }

Advantages:

  • Increases readability
  • One less keyword to remember
  • Free it for other use
  • People coming from other languages might be familiar with it (i.e. Haskell)
  • Consistent with ability to arbitrarily name parameters in explicit lambdas: x -> f(x)

Disadvantages:

  • None… I think
1 Like

What is “name”? It is undefined.

I’m not sure how allowing to use an arbitrary, undeclared name would be familiar to people coming from any other language, because I haven’t seen this feature anywhere else. In Haskell, the lambda parameter name is explicitly declared, so I’m not sure why this would be familiar to Haskell users.

Also, real code is never a single line. If I encountered such a line in an actual program, I’d have to spend a lot of time trying to understand where “name” comes from - is it a variable from an outer scope? inherited from a base class? imported via an alias? When I see “it”, it’s immediately clear what this means.

Not to mention all the confusion that would arise if you meant to refer to a specific function or variable from an outer scope, made a typo, and Kotlin would interpret it as the lambda parameter according to the “a parameter name to your liking” rule that you propose.

3 Likes

You are right I mixed something up. Haskell’s case of allows to destructure functions and assign arbitrary names:

case box of
    Just content -> print content
    Nothing      -> print "Nothing inside"

For regulary functions you still need to declare them. Maybe I was just confused because I didn’t remember having to find a keyword to refer to the only element in Haskell:

map toUpperCase ["Bob","Eva","Zoe"]

Is there a similar way of achieving that? Java allows method references.

https://kotlinlang.org/docs/reference/reflection.html#function-references

I see it cannot be used for overloaded functions. When the new syntax that allows parameter types is planned?

The documentation here is somewhat misleading and will be updated. No new syntax is planned.

I see… If you plan to update the docs, can you consider adding why it isn’t planned? Thanks!

The updated docs are now live, and I hope it’s clear from them why there isn’t any need for any new syntax.

1 Like

@yole That’s crystal clear! Thanks

I have an idea of how to get the advantages from a similar syntax without the mentioned disadvantages.

  • You can:
    • Make to use $ before the lambda scope (before {)
    • Make to start the name of the parameter with $
  • Why this helps:
    • I can not accidentally mix up common captured variables and implicit parameters (now it is insensitive to them)
    • I can guess from such implicit parameter what it is (not like it that can correspond to anything in the world)
    • Syntax is still laconic
    • It is also insensitive to nested lambdas parameter names:
      • Lambda, marked as $ must use one (not 0 or 2+) new implicit parameters.
      • So, when you would try to rename 2 parameters such way that they have the same name, You would have compilation error.
      • Actually, that is not real insensitivity, but there is no implicit converting from (X) -> T to () -> T or something like that.
      • The attitude when there are collisions is similar to one when the explicit syntax is used, but here we get an error, but not just warning.
  • Of course, using any of the approaches of implicit parameter name is bad when you have a big lambda.
  • The comparison of syntaxes:
    • Explicit
      { cat -> feed(cat) }
      
    • it
      { feed(it) }
      
    • My idea
      ${ feed($cat) }
      
  • The syntax may be simplified more I think

So what do you think of it?

it as variable name is cruel,
fun as short form of function is awful,
@annotations notate all the stuff where the language has no better solutions
BUT using the $dollarsign as variable prefix is even worse then all above

Ok, do you have anything to suggest then?
You can

  • use it@bettername, but I find it even more awful
  • give no requirements for variable name and highlight it in the IDE then.
    It is still better than just original idea because no problem with sensibility will appear.
    Of course, it is a bad idea to use it big lambdas.

I suggest you stick to using it for only single-line lambdas (that don’t contain further nested lambdas), and explicit names everywhere else. Anything else is probably going to introduce more problems than it solves. Having to add cat -> isn’t significant burden.

I see. The thing I mean is connected with similarity of programming languages and natural languages.
I suppose

/*When I found that */pets.all { it is Cat }
  • cats.map { cat -> cat.name } to be similar to ‘pets where for a cat I choose name of the cat’
  • .map { it.name } to be similar to ‘pets where I choose name of the them’
  • .map ${ $cat.name } to be similar to ‘pets where I choose name of the the cats’

So I find first sentence very innatural, the second does not say that those pets are cats, so I suggested to create something like what is written in the last one.

I would always prefere explicit name -> name.toUpperCase just not to be ambiguous. What if someone inserts a line name = “anonymous” before your line of code. How should that code behave?
You would not know what the writer’s intention was. It’s nice not to read much useless code but imho even when it was possible you should not use it

2 Likes

When using the last mentioned approach, (.map ${ $cat.name }) you don’t have that problem because the usual variable can not be named with $someName.

You are right. With your approach you do not have the problem I saw with the original post. But I’d still prefer the lambda with explicit cat -> …
Imho you should care about the most readable and therefore maintainable code. About taste can not be argued :smiley: