forEach with elements as the receivers

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.

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.

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.

1 Like

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.

1 Like

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

2 Likes

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

1 Like

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.

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…

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.

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.

2 Likes

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.

1 Like

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).

Personally I prefer withEach, or the syntax:

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

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: )

2 Likes

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

1 Like

How about

collection.asEach {  someFunction() }

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

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.

2 Likes

I’d be concerned about using -> to force a scope change within forEach. The notion of forEach behaving in two different ways also concerns me. I think both have accessibility concerns.

Also, I think the implications here might be much larger. Given the new paradigm, where else should it be applied for consistency’s sake? Should apply be deprecated in favor of this ->. if so, what does that do to the community documentation (blogs, videos, open source samples). Removing apply or providing duplicate functionality will be painful for newcomers who run into any legacy community documentation. I think that’s dangerous for a new language.

Maybe my concerns are overblown, so I’d be interested to hear counterpoints, clarification, or corrections on them.

It seems we have the tools (functions) to perform the actions to begin with. If we use those existing functions, then this sort of functionality would just be a wrapper/helper and we could think of names in terms of what tools are wrapped.

In terms of apply, we might iterate across a collection using onEach, applying as we go. That would leave us with onEachApply:

/**
 * Applies specified function [block] on each element with `this` value as its receiver and returns
 * the collection afterwards.
 */
public inline fun <T, C : Iterable<T>> C.onEachApply(block: T.() -> Unit): C {
    return onEach {
        it.apply(block)
    }
}

run would similarly be onEachRun:

/**
 * Performs the given [action] on each element with `this` value as its receiver and returns the
 * collection afterwards.
 */
public inline fun <T, C: Iterable<T>> C.onEachRun(action: (T) -> Unit): C {
    return onEach {
        it.run(action)
    }
}

with doesn’t seem useful for collection iteration (am I wrong?). That would cover all the receiver mechanisms in Standard.

This is straight forward enough that the documentation for these new functions is essentially a merging of the docs for the functions being wrapped.

Given that both run and apply return a value, it doesn’t make sense to me for there to be a forEachXxx since the results of apply or run would be discarded. Basically, apply and run return a value and forEach returns Unit, making them conceptually incompatible. That probably is pedantic. Anyone apposed to such a notion could still use onEachApply and onEachRun and discard the results if they don’t want them - making the pedantic nature of the decision non-problematic. I would go that route until such time a function that returns Unit is written into Standard - if that ever happens.