While modifiers have a scoping bug?!

irb> puts(line) while line = gets
this is test line
[EOF]
NameError: undefined local variable or method `line’ for main:Object
from (irb):1

The Pickaxe says on page 354 that unless the expression (on the left of
the while) is not a block, then the loop gets executed ZERO or more
times. So it has to evaluate the condition BEFORE the expression, which
ought to assign a value to “line” (thus defining it).

This will work, but shouldn’t be necessary:

line = nil
puts(line) while line = gets

Any insight would be much appreciated!!!

puts(line) while line = gets

The Pickaxe says on page 354 that unless the expression (on
the left of the while) is not a block, then the loop gets
executed ZERO or more times. So it has to evaluate the
condition BEFORE the expression, which ought to assign a
value to “line” (thus defining it).

Lexically, “puts line” comes first. Although “while line =
gets” is executed first and it does set /a/ (not /the/) line,
it’s not yet available for “puts”.

line = nil
puts(line) while line = gets

Now it’s the same “line”…

gegroet,
Erik V. - http://www.erikveen.dds.nl/

On Jun 28, 2006, at 1:36 PM, Mr Beev wrote:

which

Posted via http://www.ruby-forum.com/.

Erik already answered but I’ll throw in my two cents. The first
assignment of a local variable also declares it. What this means is:

puts(line) while (declare line; line = gets)

line is not in scope for puts(line) yet. Ruby creates it’s lexical
scopes for local vars by looking top to bottom, left to right at
parse time.

2006/6/28, Mr Beev [email protected]:

This will work, but shouldn’t be necessary:

line = nil
puts(line) while line = gets

Any insight would be much appreciated!!!

Note, usually you cannot rely on IRB when it comes to scoping and
local variables. It behaves differently than normal Ruby code. But in
this case it’s right:

robert@fussel ~
$ ruby -e ‘puts line if line = gets’
d
-e:1: undefined local variable or method `line’ for main:Object
(NameError)

robert@fussel ~
$ ruby -e ‘def t; puts line if line = gets; end; t’
d
-e:1:in t': undefined local variable or method line’ for main:Object
(NameError)
from -e:1

The reason, as has been pointed out already is that the assignment
appears after the read access. A solution is to use “and”:

robert@fussel ~
$ ruby -e ‘line = gets and puts line’
s
s

robert@fussel ~
$

Kind regards

robert