Variable / Method Ambiguity

the following program for showing Variable / Method Ambiguity

def a
print “Function ‘a’ called\n”
99
end

for i in 1…2
if i == 2
print “a=”, a, “\n”
else
a = 1
print “a=”, a, “\n”
end
end

will produce the result:

a=1
Function ‘a’ called
a=99

(as described in the PickAx2 book, p. 329)

So at first I thought a Ruby program is interpreted? If interpreted,
then the interpreter will see the “a = 1” at first as treat “a” as a
variable, and then the second time it sees “a”, the interpreter should
treat it as a variable again, not as a method. So does that mean a
Ruby program is not interpreted but compiled into some bytecode first?
But then, sometimes I run a Ruby program and then it can run all the way
until it see an “undefined local variable”… so that means it probably
is not compiled… or else it would have stopped without running
anything at all.

So is a Ruby program interpreted or compiled?

So is a Ruby program interpreted or compiled?

interpreted.

On Sep 17, 12:49 am, “David A. Black” [email protected] wrote:

No, because there’s no such variable in scope. The second time through
the loop, there’s no assignment to a, and the first variable a has
gone out of scope. So the only thing that “a” could mean, outside of
an assignment, is the method a.

wow… i thought the “a” variable is kind of like in C or Python:

for (i = 1; i <= 2; i++) {
int a;

if (i==2) {

} else {

}

}

so that the “a” exists all inside the for loop… maybe that’s not
right.

now, we can view the variable “a” as existing in the else block but no
where else in the original Ruby code?

Hi –

On Mon, 17 Sep 2007, Summercool Summercool wrote:

else

(as described in the PickAx2 book, p. 329)

So at first I thought a Ruby program is interpreted? If interpreted,
then the interpreter will see the “a = 1” at first as treat “a” as a
variable, and then the second time it sees “a”, the interpreter should
treat it as a variable again, not as a method.

No, because there’s no such variable in scope. The second time through
the loop, there’s no assignment to a, and the first variable a has
gone out of scope. So the only thing that “a” could mean, outside of
an assignment, is the method a.

David

Summercool Summercool wrote:

So is a Ruby program interpreted or compiled?
It is interpreted but before being interpreted it is parsed. And whether
a symbol is a variable or not is determined at parse time: when the
parser sees the assignment “a = 1”, it assumes that ‘a’ is a variable
for all subsequent lines of the source code, until the end of the
method or block where the assignment occured. It is has nothing to do
with the order in which the code is executed.

Also you’ll notice that the “undefined local variable” message is
actually “undefined local variable or method”, because ruby can’t know
if the unknown symbol was supposed to be a method or a variable.

Daniel

On 9/17/07, David A. Black [email protected] wrote:

variable, and then the second time it sees “a”, the interpreter should
treat it as a variable again, not as a method.

No, because there’s no such variable in scope. The second time through
the loop, there’s no assignment to a, and the first variable a has
gone out of scope.

so this is lexical scoping, then?

So the only thing that “a” could mean, outside of
an assignment, is the method a.

David

-jf


In the meantime, here is your PSA:
“It’s so hard to write a graphics driver that open-sourcing it would not
help.”
– Andrew Fear, Software Product Manager, NVIDIA Corporation

On Sep 17, 2007, at 12:08 PM, Jeffrey ‘jf’ Lim wrote:

interpreted,
so this is lexical scoping, then?
No, it is just that Ruby has a single-pass parser. The parser needs
to decide if an identifier is a local variable or a zero-argument method
before it has seen the entire text of the file (no look-ahead). Until
the parser sees an assignment of the form “a = …” it assumes
that ‘a’ is a method call.

So if/then/else statements do not create new lexical scopes.

Gary W.

7stud – wrote:

David Black wrote:
The second time through
the loop, there’s no assignment to a, and the first variable a has
gone out of scope. >

Wait a minute. ‘a’ has gone out of scope?

for i in 1…2
if i == 1
a = 10
print “a=”, a, “\n”
else
puts a
end
end

puts “*#{a}”

puts a

–output:–
a=10
10
*10

In ruby, for loops and if clauses don’t create a scope.

David A. Black wrote:

No, because there’s no such variable in scope. The second time through
the loop, there’s no assignment to a, and the first variable a has
gone out of scope. So the only thing that “a” could mean, outside of
an assignment, is the method a.

That doesn’t seem to bear out. If you switch the if statement around so
that the assignment happens first:

def x
print “Function ‘x’ called\n”
99
end

for i in 1…2
if i == 1
x = 10
print “x=”, x, “\n”
else
print “x=”, x, “\n”
end
end

the output is:

x=10
x=10

The second time through that loop, there is no assignment to x and the
previous x has gone out of scope, yet the else clause’s use of x does
not result in a method call.

As p. 329 in pickaxe2 carefully explains, it is a ruby parsing rule that
determines what x means. As I read the rule, and as Daniel explains,
and as the two examples show(the ‘a’ example and the ‘x’ example), the
rule is: if there is any code that has x=val on a line before the use of
x, then x will be interpreted as a variable. If there is no assignment
to x on a line higher in the code, then x will be interpreted as a
method call.

From: 7stud – [mailto:[email protected]]

In ruby, for loops and if clauses don’t create a scope.

irb(main):001:0> if false
irb(main):002:1> x
irb(main):003:1> end
=> nil
irb(main):004:0> x
NameError: undefined local variable or method `x’ for main:Object
from (irb):4
irb(main):005:0> if false
irb(main):006:1> x = 5
irb(main):007:1> end
=> nil
irb(main):008:0> x
=> nil

they can introduce a var (under the existing local scope of course).
i think its in the assignment behaviour if you look at it. parser sees
assignment even if code is not executed.
ruby just try to be friendly, but you can be sloppy if you want to and
ruby will not give you an error :slight_smile:
again, i think this is a faq.

kind regards -botp

7stud – wrote:

That doesn’t seem to bear out. If you switch the if statement around so
that the assignment happens first:

def x
print “Function ‘x’ called\n”
99
end

The difference between the both examples is the following:

Ruby parses this:

for i in 1…2
if i == 2
print “a=”, a, “\n”

Here Ruby decides, that “a” must mean the a method and creates the call-method node in its tree.
else
a = 1

Here Ruby decides, a is a local variable.
print “a=”, a, “\n”

Here Ruby creates a evaluate-local-variable node in its tree.
end
end

In your example:

for i in 1…2
if i == 1
x = 1

Here Ruby decides, “x” is a local variable.

    print "x=", x, "\n"

Here Ruby creates a evaluate-local-variable node in its tree.

else
    print "x=", x, "\n"

Sticks to its former decision, that “x” is local variable, and
creates a evaluate-local-variable node in its tree.
end
end

This is an interaction between parsing and execution or ruby code, and
it can be a bit surprising. The later execution (== comparisons, etc.)
doesn’t alter the behavior of the parser, which does its jobs earlier.

Hi,

7stud – wrote:

David A. Black wrote:

As p. 329 in pickaxe2 carefully explains, it is a ruby parsing rule that
determines what x means. As I read the rule, and as Daniel explains,
and as the two examples show(the ‘a’ example and the ‘x’ example), the
rule is: if there is any code that has x=val on a line before the use of
x, then x will be interpreted as a variable. If there is no assignment
to x on a line higher in the code, then x will be interpreted as a
method call.

Please, look at this 2 examples of “parse-time”:
1)

pp ParseTree.translate(‘bar = 3
define_method(:foo) do
bar
end’)
[:block,
[:lasgn, :bar, [:lit, 3]],
[:iter, [:fcall, :define_method, [:array, [:lit, :foo]]], nil, [:lvar,
:bar]]]

pp ParseTree.translate(‘bar = 3
def foo
bar
end’)
[:block,
[:lasgn, :bar, [:lit, 3]],
[:defn, :foo, [:scope, [:block, [:args], [:vcall, :bar]]]]]


In 1) we see a :lvar node, whereas in 2) we see a :vcall. From my
interpretation of p.329 of pickaxe2 i do not agree with the 2nd case
(but probably it’s my problem - comment please). In the 2nd case, IMHO,
we should see a lvar node.
This may seem a detail, but i was bitten by that a few minutes ago. Let
me show a simplified example:

bar = “test”
c = Class.new
c.class_eval do
def foo
bar
end
end

c.new.foo
NameError: undefined local variable or method `bar’

i was expecting to get “test”

The (hack) “solution” (it’s a hack because IMHO i shouldn’t have to do
that):
bar = “test”
c = Class.new
c.class_eval do
define_method(:foo) do
bar
end
end

c.new.foo
“test”

Note: only one more thing, since ruby 1.8 have a “problem” with block
(it can’t get other blocks - &block in argument) this could be a
problem. I know you can hack these thing through a method - but that’s
another hack :P… too much hacks for me :slight_smile:

I would appreciate very much all your comments about the current
behavior of ruby (1.8).

Regards,
Vasco Andrade e Silva