Give syntax for using the 'for' shortcut on multiple arrays.
Iteration over multiple enumerables at once is not simple or intuitive, involving explicit indexing into each of the enums (fine for people who came from C), and what is being iterated over is not well described by the loop control of the iteration (for example: '[a.length, b.length].max.times do |i| puts a[i],b[i] end').
Allow comma delimited list of Enumerables to be zipped together and iterated over.
for x,y,z in enum_1,enum_2,enum_3 puts x,y,z endwould be a shortcut to
enum_1.zip(enum_2, enum_3).each do |x,y,z| puts x,y,z end
The shortcut wouldn't carry over and be able to help the normal use of #each, as 'for' is already doing some magic, and it would have to be doing more with this.
To be able to mix Hashes, Arrays, &c., further magic would have to happen, such as calling #to_a on all enums passed as arguments to #zip (possibly moving that behavior to #zip itself).
(BTW, I believe #zip already converts everything to arrays. See enum_zip() in enum.c.)
I prefer the idea of having a wrapper around #zip to the expansion of 'for'. For example:
module Kernel
def over(*enums)
enums[0].zip(*enums[1..-1]).each {|a| yield a}
end
end over([1,2,3],[4,5,6]) do |x,y|
p "x is #{x}, y is #{y}"
end
(There are probably many cases that aren't handled correctly by this, but it's just to illustrate the idea.)
-- David Black
-- Zachary P. Landau
I like the 'over' syntax dblack suggested, but unless it is accompanied with a proposal to remove 'for' completely, i think the behavior should be put in both places.
Does "don't like 'for'" stem from it doing magic in the background, and therefore that it can lead to obfuscation, or is it just that it's a duplication of a behavior more concisely expressed with #each? Or something else? I think the obfuscation argument has validity, that 'for' does not clearly show that it is calling #each. However, i disagree that it should be removed on account of duplication; the 'for' syntax is more naturally read and much easier for many people to understand before they've gotten the hang of blocks. In which case, is it that the language should force people into the use of blocks?
-- Martin ChaseA bit of a can of worms :-) Personally I would like 'for' to disappear, for the very reason you outline -- namely, that it is a sort of bridge from other languages to Ruby. I do think that the language should force people to use blocks. People *like* blocks :-)
Anyway, not to stray into a whole philosophical thing... (nor, btw, am I ascribing any particular philosophy of language relations to you; I'm just thinking out loud) I understand your point about the symmetry: as long as there's 'for', an extension of 'for' should also be 'for'. I guess I'd rather see this not happen, unless Matz says that there's no chance at all that 'for' will ever be phased out. (The point being: if it does happen, it would make 'for' harder to phase out.)
-- David Black
Why not use an iterator primitive instead?
require 'iterator' a = %w(a b c d e).create_iterator b = (0..4).to_a.create_iterator while a.has_next?
p [a.current, b.current]
a.next
b.next
end a.close b.close
-- Simon Strandgaard
Simon, your solution, tho usable, is not a solution to the problem as stated above of there being too much setup (and in your case, tear down) for a multi-enumerable iteration. The problem is not that we can't do it, it is that doing so is not simple and straight-forward.
David, you're right this would make 'for' harder to give up. I am now neutral, however, on whether or not it should go away. Blocks give ruby its style in many ways, but 'for' is an unmistakable pattern that many find comforting.
-- Martin ChaseI am thinking of another case where this idea might be more common, when iterating through a hash; currently the usual way to get the key and value would be :
h = { "a" => 100, "b" => 200 }
h.each {|key, value| print key, " is ", value, "\n" }
another way we can do this could be..
h = { "a" => 100, "b" => 200 }
for key, value in h
print key, " is ", value, "\n"
end
I strongly believe the using the for..in statement would enhance the readability and the naturalness of the code.
-- Sam Lie
It's hard to argue naturalness in the abstract (I won't even try :-) but in the context of Ruby, iterating through an Enumerable object with #each is a bread-and-butter technique. It's debateable whether 'for' has the feel of something slightly out of keeping with idiomatic Ruby, but I don't think there's any chance that #each does :-) -- David Black
h = {"a"=>100, "b"=>200}
for (k, v) in h
print k, " is ", v, "\n"
end
Sam's proposol would also be at odds with this RCR.
I would dream of the possibility to have a better version of zip in Ruby. The current version has the disadvantage to build (probably large) temporary arrays, and this behaviour would be masked even more if the for syntax is extended like this RCR proposes it. In my dream version zip would use generators to fetch values from the enum arguments of zip, without building temporary arrays. It's easy to implement a zip with the ruby generator module, but using this zip is painfully slow (ruby continuations are pretty slow), so the current version is much faster even for big temporary arrays.
So, I like the extended for syntax, but fear the current implementation problems.
-- Florian Frank
Back to RCRchive.
RCR Submission page and RCRchive powered by Ruby, Apache, RuWiki (modified), and RubLog