elves / elvish

Powerful scripting language & versatile interactive shell
https://elv.sh/
BSD 2-Clause "Simplified" License
5.53k stars 297 forks source link

Change the for loop to create a new binding per iteration #1724

Open hanche opened 9 months ago

hanche commented 9 months ago

As mentioned in chat today, this could catch some by surprise:

⬥ for x [a b c] { put { constantly $x} } | each  {|f|  ($f) }
⮕ c
⮕ c
⮕ c

I suggest creating a new binding for the loop variable with each iteration of the loop, essentially turning for x $seq { … } into all $seq | each {|x| … }.

This is of course a backward incompatible change. In particular, some users might use the value of the loop variable after the loop is done, to see what was the last value handled. This would now have to be done manually.

Also, it is conceivable that this would be a performance problem with loops iterating a lot, if all those variable bindings now have to be handled by the garbage collector. One might consider having the compiler analyze the code and reuse the variable binding if it is not captured inside the loop.

krader1961 commented 6 months ago

This is effectively the same issue as https://github.com/golang/go/discussions/56010 for Go itself. And it seems clear that Go is going to change its loop var binding behavior since doing so is going to break very few programs and result in a big reduction in bugs. Elvish should make the same change.