`do for item in list` ? #2518

Open
jashkenas opened this Issue Aug 28, 2012 · 21 comments

Projects

None yet
@jashkenas
Owner

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?

@vendethiel
Collaborator

+1 a lot

@epidemian

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

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
Closed

let for #164

@ichernev

+1

Another variant may be

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

similar to for own.

@zeekay
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
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
STRd6 commented Mar 4, 2013

What about:

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

JavaScript has had iterators for a while now.

@vendethiel
Collaborator

coffeescript targets IE6.

@vendethiel
Collaborator

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

@monolithed

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

@nfour
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
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) ->
@farmdawgnation

+1 for something that does this in one line.

@akre54
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
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
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
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.

@benmosher

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

@carlsmith

+1 One question...

foo = for item in items do -> proc item # what's foo?
@connec
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