`do for item in list` ? #2518

jashkenas opened this Issue Aug 28, 2012 · 21 comments


None yet

An interesting proposal raised by @lehni, here:

#2382 (comment)

... is to somehow combine the do and for keywords to give you a quick and easy way to write a loop that closes over its variables ... without hiding the fact that you're working with an implied inner function, and all of the scope changes that involves. I think it might work out nicely.

do for num in [1, 2, 3]

... becomes the equivalent of:

for num in [1, 2, 3]
  do (num) ->

Any ideas?


+1 a lot


What about

for num in [1, 2, 3] ->


At least for me the symbol -> is kind of a synonym for "new scope starts here!".

Edit: Not exactly a synonym. class also introduces a new scope without the need for ->.

connec commented Aug 28, 2012

I would prefer to somehow allow do right after a for expression and/or set the right arguments for the closure as per @lehni:

for num in [1, 2, 3] do ->

equivalent to

for num in [1, 2, 3] then do (num) ->

Though I think the existing then do... form provides possibly the best mix of clarity and convenience without adding new syntax or semantics, though it certainly gets a bit duplicative if you're using destructuring etc.

for { id, title, content } in sections then do (id, title, content) ->

I assume that this would work as expected?

do for num, idx in [1, 2, 3]
  console.log 'idx:', idx, 'num:', num

I agree with @epidemian that -> does a good job of announcing new scope. For this reason I find for v in a do -> clearer than do for v in a, but perhaps the latter would feel more natural as it became more familiar. Actually, in the time I've spent writing this comment I've changed my mind. -> as shorthand for a function that receives one argument (or two, if the index is passed in as well) feels too magical. I may be wrong, but I believe that -> not preceded by (...) currently always means this function takes no arguments. I'm warming to do for, in other words.

@vendethiel vendethiel referenced this issue in satyr/coco Sep 5, 2012

let for #164



Another variant may be

for scoped i in [1,2,3]
  console.log i

similar to for own.

zeekay commented Oct 3, 2012

I am a fan of the syntax proposed by @connec. for num in [1, 2, 3] do -> reads very well.

joliss commented Oct 30, 2012

@jashkenas, I think that's a great idea!

@lehni's and @connec's syntax for num in [1, 2, 3] do -> was what I had tried initially, naively hoping that it would "just work". So to me it seems like the most intuitive variant. I haven't thought about whether it would fit well into the language spec though.

That said, IMHO either syntax would be a great improvement.

STRd6 commented Mar 4, 2013

What about:

[1, 2, 3].forEach (num) ->
  console.log i

JavaScript has had iterators for a while now.


coffeescript targets IE6.


bump after that got asked on irc

for num in [1, 2, 3] do ->

note that this is valid for a in b do (-> c) then ... is valid


+1 for:
for num in [1, 2, 3] do -> ...

nfour commented Feb 18, 2014

Any followups? Just found myself writing a loop like this and trying to minimize the amount of indentation thus intuited for key of obj then do ->.

Would prefer if

    for tabKey, apiKey of pageApiMap then do (tabKey, apiKey) ->

Could be shorthanded to

    for tabKey, apiKey of pageApiMap then do ->

Where the do function's parameters are implicitly passed when you don't specify them; because I can't see a scenario where you wouldn't want the parameters passed to a new anonymous function.

connec commented Feb 18, 2014

You could almost 'merge' for and function syntax into something like

for (key, value) of object ->
# for key, value of object then do (key, value) ->

for (value, index) in array ->
# for value, index in array then do (value, index) ->

for (key) of object ->
# for key of object then do (key) ->

for (value) in array ->
# for value in array then do (value) ->

# This is perhaps a bit too interesting
for (value, index, a = 1) in array ->
# for value, index in array then do (value, index, a = 1) ->

+1 for something that does this in one line.

akre54 commented May 7, 2014

I ran into this today and was surprised it wasn't in the language. +1 for including in core.

lehni commented May 7, 2014

Please note that my proposal kept the sequence of the various components in line with how things work already in CS. So this:

for item, index in [1, 2, 3, 4, 5] then do (item, index) ->
  console.log item, index

Would become:

for item, index in [1, 2, 3, 4, 5] do ->
  console.log index, item
STRd6 commented May 7, 2014

It's worth noting again that you can already do this with built-in array methods.

[1..5].forEach (item, index) ->
  console.log item, index

If you need to support IE6-8 you can apply a polyfill as described here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Polyfill

connec commented May 11, 2014

It's not just about the presence of Array#forEach, it's also now an issue of consistency due to for ... in being the canonical way of performing iteration in CoffeeScript, Array#forEach is always a bit surprising.

I'd definitely rather see for ... then do (...) -> than Array#forEach, and I'd prefer to see, e.g. for (a, b) in c -> (or one of the other proposals) than either.


+1 for this in core. I'm continually surprised that I have overwritten earlier variables by (poorly) choosing the same name for a loop variable somewhere later. I also run into this doing object deconstruction assignment, i.e.

value = ...
someFunction(key, value) for {key, value} in [D3 associative array entries]

Now value's original value (heh) has been lost. Again, I can avoid this by renaming value in the earlier case, but it generally takes an execution and the resulting (often surprising/confusing) exception to find it.

Array#forEach is a decent solution for now (and the value ellision is desirable in my case), but like @connec, I'd rather use a CS core construct.


+1 One question...

foo = for item in items do -> proc item # what's foo?
connec commented Aug 27, 2014

It would be equivalent to:

foo = for item in items then do (item) -> proc item
# or
foo = ((do (item) -> proc item) for item in items)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment