6

Why does this work:

a = [1, 2, 3]
while n = a.shift
  puts n
end

while this doesn't:

a = [1, 2, 3]
puts n while n = a.shift

It works only if I initialize n in advance:

a = [1, 2, 3]
n = nil
puts n while n = a.shift
sawa
  • 165,429
  • 45
  • 277
  • 381
Neves
  • 158
  • 2
  • 10
  • http://stackoverflow.com/q/21740291/ – Jörg W Mittag Sep 30 '15 at 06:35
  • There are a number of parser issues related to LALR descent that affect Ruby post-conditions. They are bugs, but nobody ever opens bug reports about them. See [this related answer](http://stackoverflow.com/a/25820190/1301972) for a similar problem with the :if_mod token. – Todd A. Jacobs Sep 30 '15 at 10:01

3 Answers3

4

That is, in general, an interpreter problem, that could not appear in languages with local variable bubbling, like javascript.

The interpreter (reading from left to right) meets right-hand-operand n before any mention of it.

The more I think about it, the more I am convinced it is a bug in ruby interpreter. As @Cary pointed out, the control flow is in fact the same:

a = [2, 3]
n = 1
puts n while n = a.shift
#⇒ 2
#⇒ 3

No trail of 1 in the output above.

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
  • Good explanation. You might want to add another case: the second example preceded by `n = 0`. – Cary Swoveland Sep 30 '15 at 04:26
  • Thanks. In fact, the second example with `n = 0` preceeded, is written in the pseudocode _exactly_ as the first one, that is why I decided to omit it. *UPD*: Oh, wait. I will, thx. – Aleksei Matiushkin Sep 30 '15 at 04:30
  • I suggested that because I thought some readers might think `0` might be printed in that case. – Cary Swoveland Sep 30 '15 at 05:06
  • @CarySwoveland thanks a lot, actually my previous answer was confusing, I have it completely re-written. – Aleksei Matiushkin Sep 30 '15 at 05:39
  • The control flow is irrelevant. The `n` in `puts n` is a method call since at that point a local variable called `n` isn't defined according to the from left to right reading parser. It's just a local variable quirk that would require special-casing. – cremno Sep 30 '15 at 08:34
  • It's not a bug in the interpreter. It's a misfeature of the LALR descent parser in the way it handles post-condition tokens. – Todd A. Jacobs Sep 30 '15 at 10:04
1

Regarding: puts n while n = a.shift,

it will pares puts n first, but n is undefined at that point. Ruby is a dynamically typed language; you don't declare variable type explicitly, but you should assign a value to variables.

For example:

irb(main):027:0> xyz
NameError: undefined local variable or method `xyz' for main:Object
irb(main):028:0> xyz = 1
=> 1
pangpang
  • 8,581
  • 11
  • 60
  • 96
1

n is undefined at the time you attempt the first puts. The condition, and corresponding shift, is only checked after the puts has been evaluated. An alternative which will work as you expected would be

a = [1, 2, 3]
puts a.shift while a.length > 0
pjs
  • 18,696
  • 4
  • 27
  • 56