Reputation: 3500
Does anybody why I can write this:
ruby-1.8.7-p302 > a = %w( a b c)
=> ["a", "b", "c"]
ruby-1.8.7-p302 > while (i = a.shift) do; puts i ; end
a
b
c
=> nil
Which looks like passing a block to while. And not:
while(i = a.shift) { puts i; }
Is it because the "do" of the while syntax is just syntaxic sugar and as nothing to do with the "do" of a block?
Upvotes: 9
Views: 3202
Reputation: 369458
Is it because the
do
of thewhile
syntax is just syntaxic sugar and as nothing to do with thedo
of a block?
More or less, yes. It's not syntactic sugar, it's simply a built-in language construct, like def
or class
, as @meagar already wrote.
It has nothing to do with the do
of a block, except that keywords are expensive and so reusing keywords makes sense. (By "expensive" I mean that they limit the programmer in his expressiveness.)
In a while
loop, there are two ways to separate the block from the condition:
do
keyword andThere are, in turn, two different expression separators in Ruby:
;
andSo, all three of the following are valid:
while i = a.shift do puts i end # do
while i = a.shift; puts i end # semicolon
while i = a.shift
puts i end # newline
[Obviously, that last one wouldn't be written that way, you would put the end
on a new line, dedented to match the while
. I just wanted to demonstrate what is the minimum needed to separate the parts of the while
loop.]
By the way: it is highly un-idiomatic to put the condition in parentheses. There's also a lot of superfluous semicolons in your code. And the variable name i
is usually reserved for an index, not an element. (I normally use el
for generic elements, but I much prefer more semantic names.)
It is also highly un-idiomatic to iterate a collection manually. Your code would be much better written as
a.each(&method(:puts)).clear
Not only is it much easier to understand what this does (print all elements of the array and delete all items from it), it is also much easier to write (there is no way to get the termination condition wrong, or screw up any assignments). It also happens to be more efficient: your version is Θ(n2), this one is Θ(n).
And actually, that's not really how you would write it, either, because Kernel#puts
already implements that behavior, anyway. So, what you would really write is this
puts a
a.clear
or maybe this
a.tap(&method(:puts)).clear
[Note: this very last one is not 100% equivalent. It prints a newline for an empty array, all the other ones print nothing.]
Simple. Clear. Concise. Expressive. Fast.
Compare that to:
while (i = a.shift) do; puts i ; end
I actually had to run that multiple times to be 100% clear what it does.
Upvotes: 13
Reputation: 239311
while
doesn't take a block, it's a language construct. The do
is optional:
while (i = a.shift)
puts i
end
Upvotes: 7