Will "It" variable stay or go?

I recall last year that "it" variable for a single parameter lambda function was planned for removal. I found that the feature is still available in the latest Kotlin compiler.

We haven't decided on this yet

I kind of like the "it" syntax from my Groovy days.  Also I find it reads well.  But it seems like the reference itself is not understood by the IDE.  What are the reasons to remove it?

1 Like

"it" doesn't play too well with nested lambdas: requires some discipline on the programmer's part to keep away from cases where the meaning of "it" gets unclear because of nesting

1 Like

Those are very good reasons.  Groovy function's scoping rules can be extremely confusing for library writers. As much as I like "it" my vote would be to remove it to avoid that type of confusion.  I've been selling Kotlin to my colleagues as being the first alternative JVM language that is going for Simpler than Java.  I'm hoping Kotlin jealously sticks to that theme.

"it" variable saves about 2 extra keystrokes. If the choice is between that and learning one extra concept (and its exceptional case) on the language, I would prefer to remove it.

Can you please provide some concrete example where this starts to be a problem? I tried to experiment with nested lambdas and "it" always behaves as I would expected. I don't mind few extra keystrokes, what I would miss is readability.

(1..100).filter{ it > 50 }.map{ it * 2 } (1..100).filter{ x -> x > 50 }.map{ x -> x * 2 }

First line, at least for me, is much more readable and quicker comprehensible. Second line is full of arrows which are just visual noise my eyes have to filter out. What I like about Kotlin is how concise but still well readable code can be written. I would find it unfortunate to completely drop "it" because of some its edge cases. Because those simple and more often cases would be hurt.

3 Likes

 

class Tree(val data: String, children: List<Tree>)

tree.forEach {
  if (it.data != “special”) {
  it.children.filter {
  it.data == “special” // it’s NOT the same “it.data” as two lines above, but nothing suggests that in the syntax
  }
  }
}

Worse than that: sometimes it's the same "it.data": when the nested lambda does not have a parameter at all

3 Likes

Have to say I agree. I'd really hate to lose the ability to write code as in the first line. For simple scenarios it's much more elegant. I wonder if it's just a question of people applying their common sense here.

5 Likes

I've encountered this in real code and it can get confusing indeed. At the very least, it makes the programmer stop and think (=waste time) about what exactly each variable represents. On the other hand, it's one of the features that makes Kotlin such a joy to use. It results in shorter, cleaner code and it's one less variable you need to figure out a name for (which is "hard" and wastes time).

A middle-ground solution would be to restrict the implict it to a single nesting level. Any lambda inside a nested hierarchy of lambdas, where one of the above uses the implicit it, would require an explicit argument name. Not a pure solution, but covers the majority of use-cases.

A counter-argument would be that without this feature, Kotlin would look less alien to developers coming from Java 8.

2 Likes

I don't know if anything speak against it but wouldn't it be possible to make the IDE issue a warning for such a case of nested lambdas and implicit 'it' parameters Ă  la "Please consider using explicit paramaters to avoid confusion". This way the succinct nature of the implicit 'it' parameter for unnested cases stays but potentially confusing uses are pointed out by the IDE.

I admit, it would seem nicer if the language by its design disallowed such a potentially confusing situation in the first place. On the other hand, a lot of other uses of ‘it’ would then suddenly pay a tax just for the sake of avoiding an edge case. I personally like ‘it’. So I’d think that the IDE route would be a good compromise if it is possible to make it work.

4 Likes

How about to replace `it` with `this`? And additionally it will give us the ability to access to members without a qualifier, like:

users.filter { name == "Alice" }

P.S. I like `it` too :)

2 Likes

The compiler could issue an error if you try to use `it` in a nested lambda, the idea here being that the outermost scope is already defining an `it` so nested lambdas can't use the shortcut annotation any more.

This would cover most cases since it’s more common to chain lambdas than to nest them.

9 Likes

I like the "it" keyword a lot too. It saves a lot of time and not just 3 keystrokes (you write the code once, you read it a lot more) : when you see "it", you know that you are in a 1 parameter lambda and that this is the parameter (saves time scanning the lambda)

I have quite a lot of nested lambdas in my production code.  
When they don’t get flatMaped into a 1 dimensional flow (for performance/threading/simplicity reasons), I just explicitely add varible names and arrows where it makes sense.
This has never been an issue.

Isn’t this desambiguation problem with “it”, the same problem we have with “this” ?

Also, using “it” is addictive :
the code
A.(B) -> C
has already parameter “this” for A but I recently caught myself wishing the B parameter could have the “it” parameter


Also, wouldn’t the ambiguity issue be resolved with getting an ide warning when you have at least 2 nested structures (lambdas or when or whatever captures 1 argument in “it” or “this”) ?

1 Like

I have suffered through this in Groovy a lot. It can get very confusing if you nest closures. Here are my thoughts:

  • it is convenient and easy to read. If there is only one parameter. Otherwise you should be forced to explicitely name them.
  • using it should be a compiler error in nested closures. In that case the developer should always be forced to explicitely name parameters.

Is it possible to shadow names in closures (i.e. declare x in outer and in inner closure?) Should that be possible?

1 Like

Out of curiosity: how is this done in C#?

C# doesn't have an implicit "it"-like variable.

You say “For simple scenarios it’s much more elegant. I wonder if it’s just a question
”.
Which “it” yo you mean? The it from the last sentence refers to another thing than the first (which refers to “ability”).

You see, it happens in natural language too. It can be another it suddenly. No one cares. If you would really have a problem with it, than these sentences with a lot of it in it would be a problem for you too. Are they?
If a programmer can formulate and understand english sentences, then he can also figure out what “it” means in Kotlin :innocent:
And even this thread itself shows, that no one tries to distinguish the code “it” the reference “it” or the colloquial “it” (referring to nothing actually).

I could not agree more. Things can get confusing easily with many language constructs. Take the following example that uses apply(...). Should this function be removed because it might cause confusion?

Good developers know how and take the extra time to write clear code, so they do not waste their fellow developer’s and their own time in the future. So usually you use explicit names when nesting lambdas and you do not nest apply(...), but if the code remains clear you sure do not want to be prevented from doing so.

class Person {
    var name = ""
    var status = "living"
}

class PersonView {
    var backgroundColor = Color.WHITE
    var status = "enabled"
}

fun setUpPersonView() {
    PersonView().apply {
        Person().apply {
            backgroundColor = Color.RED
            name = "E. Xample"
            // Oops, disabling a person. What does that mean?
            status = "disabled"
        }
    }
}

I’m not sure why this discussion came up again. Since the thread was started, Kotlin 1.0 was released. Kotlin 1.0 guarantees backwards compatbility, and the “it” implicit parameter is part of Kotlin 1.0. Therefore, it will not be removed from the language.

3 Likes