forEach with elements as the receivers


#1

I wonder why an equivalent of forEach with elements as the receivers was not included in the Standard library.

public inline fun <T> Iterable<T>.each(action: T.() -> Unit): Unit {
    for (element in this) element.action()
}

There clearly do exist cases when iterating elements as receivers of an action is the most concise and readable code.


Force usage of "it" in .forEach{} calls
#2

There’s an issue KT-8673 tracking this request.

What currently holds it from being implemented is a lack of relevant name. Also it’s unclear whether a lot of cases would benefit from this function. If you have some, please do not hesitate to show them either here or in that issue comments.


#3

It seems finding a good name is more difficult than providing possible usage examples (which I will try to do later).
What about onEach? It may be perceived as a shortened form of the verbose “perform an action on each element”. “On” implies some direct action (unlike “for”, which just provides an argument without changing the receiver) and is luckily also short.
withEach name suggested by Sergey Igushkin in the issue above is good, because it pairs nicely with with. Although one could extend this logic further by stating that run suits even better, because run itself is an extension function (unlike with). However, runEach or eachRun would look rather awkward.


#4

onEach is already taken: http://kotlinlang.org/docs/reference/whatsnew11.html#oneach

Btw, for consistency one could want to have onEach version with receivers too.


#5

Depending on what is returned I would expect the function to be called applyOnEach or runForEach:


#6

forEach returns nothing (Unit). So would its “receiver” analog.


#7

I even thought that maybe, to prevent descending into a naming hell, a tiny syntactic sugar would help here?
Like, support lambdas decorated with something, which would be equivalent to normal lambdas but with the first argument turned into the receiver?
A hypothetical example:

list.forEach *{
    field1 = 0
    doSomething()
}

…is equivalent to

list.forEach {
    it.field1 = 0
    it.doSomething()
}

But, of course, this could be even worse than “naming hell”, because it’s too obscure and magical.


#8

Great question!
I was happy when onEach was introduced until I saw that the method had a (in my eyes) bad name and should have been named peek.
But afterwards it’s easy talking.

Maybe withEach and mapEach?
The problem with mapEach is that it kind of suggests that its purpose is to map…


#9

I think that would be to magical. This would add quite a bit of complexity without much gain IMO.
This would be the only case I can think of this would be useful.

As for a name. I would prefer runForEach as @jstuyts suggested as it is parallel to run.
I would be fine with applyForEach but that would suggest the Iterable being returned which it wouldn’t.


#10

The usefulness of this case is not so limited: having this feature would allow to get rid of run and apply methods (by using sugared calls to their counterparts). Compare, for example:

foo.let {
    it.bar()
}

foo.run {
    bar()
}

foo.let *{
    bar()
}

The language provides a sugar in the form of it argument. Why not allow the programmer to convert it to the receiver in the lambda when appropriate?

The mere existence of pairs of methods with different names but similar semantics (different only by the argument / receiver) is a complexity in itself.


#11

Ok, agreed. The problem is that due to backward compatibility let and run will never go away. I think in retrospect some sort of magic operator for lambdas would be nice as it would have given the same options as run/let, also/apply (I guess there are more examples, cant think of them right now).

Adding this operator now, would add more complexity and I think most use cases are already satisfied.
If Kotlin missed more than just runForEach than maybe it could be worth adding this operator. But I think it is too late for that.


#12

You are right.
Actually, we always have this workaround:

collection.forEach *{
    bar()
    x = 1
}

is

collection.forEach {
    with(it) {
        bar()
        x = 1
    }
}

…which is just slightly more verbose (but still noticeable in simple calls).


#13

Personally I prefer withEach, or the syntax:

list.forEach { this ->
    field1 = 0
    doSomething()
}

#14

I really like the syntax you propose. It is much less magical than the * @Inego used and IMO it is easy to understand when reading it. I would love to see this coming to Kotlin. It would probably mean the language is more accessible as you no longer have to learn the difference between run, let, also, apply, with, etc (I have to look them up every few days :blush: )


#15

Agreed, @fvasco’s { this -> ... } is an excellent idea!


#16

How about

collection.asEach {  someFunction() }

#17

Has “toEach” been suggested already? It’s a nod to “receiver” terminology.


#18

Best suggestion in the thread. Having support for { this -> ... }
I also like the naming withEach the most if said extension function is to be implemented.