parsing rule for this code?

7

7stud --

1)
class ABC
def do_something
number = 10
puts number
end
end

ABC.new.do_something

--output:--
10


2)
class ABC
def do_something
3.times do |x|
number = 10
end
puts number
end
end

ABC.new.do_something

--output:--
Line 6:in `do_something': undefined local variable or method `number'
for #<ABC:0x401bfaa4> (NameError)
from t.rb:10


Why does ruby get confused by the setter v. local variable assignment
when adding a block?
 
B

botp

...
Why does ruby get confused by the setter v. local variable assignment
when adding a block?

ruby is not confused :)

try these eg,

class ABC
def do_something
number=0
3.times do
number=10
end
p number
end
end
#=> nil
ABC.new.do_something
10
#=> 10


class ABC
def do_something
number = 0
3.times do |;number|
number=10
end
p number
end
end
#=> nil
ABC.new.do_something
0
#=> 0

best regards -botp
 
J

John Feminella

As a rule of thumb, variables exist until you reach the "end" or
closing brace of the innermost block that they're still contained in.
In your case, you have this:
=C2=A0 =C2=A0def do_something
=C2=A0 =C2=A0 =C2=A0 =C2=A03.times do |x|
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0number =3D 10
=C2=A0 =C2=A0 =C2=A0 =C2=A0end
=C2=A0 =C2=A0 =C2=A0 =C2=A0puts number
=C2=A0 =C2=A0end

The local variable `number` is created with the value 10 and then
immediately discarded. This happens three times, since the block
executes three times.

The goal of the next statement is to print a local variable called
`number`. But there is no such local variable in this block. So Ruby
rightfully complains that you didn't define it. If instead you had
written this:
=C2=A0 =C2=A0def do_something
number =3D 0 # create `number` in this lexical scope
=C2=A0 =C2=A0 =C2=A0 =C2=A03.times do |x|
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0number =3D 10
=C2=A0 =C2=A0 =C2=A0 =C2=A0end
=C2=A0 =C2=A0 =C2=A0 =C2=A0puts number
=C2=A0 =C2=A0end

then it would work as you probably expect.

~ jf
--
John Feminella
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: http://stackoverflow.com/users/75170/
 
7

7stud --

Thanks. I got confused by the error message--it lead me to believe the
problem was a setter v. variable assignment parsing problem. Instead it
was a beginner scope problem.
 
7

7stud --

Ok, the following code exhibits the problem I was trying to demonstrate:

class Roulette
def method_missing(name, *args)
person = name.to_s.capitalize

3.times do
number = rand(10) + 1
puts "#{number}..."
end

#puts "#{person} got a #{number}"

end
end

Roulette.new.xxx

If I uncomment the commented line, I get an infinite loop. Why? I'm
pretty sure that is a local variable assignment v. setter problem.
 
J

John W Higgins

[Note: parts of this message were removed to make it a legal post.]

Good Afternoon,

Ok, the following code exhibits the problem I was trying to demonstrate:

class Roulette
def method_missing(name, *args)
person = name.to_s.capitalize

3.times do
number = rand(10) + 1
puts "#{number}..."
end

#puts "#{person} got a #{number}"

end
end

Roulette.new.xxx

If I uncomment the commented line, I get an infinite loop. Why? I'm
pretty sure that is a local variable assignment v. setter problem.
It's not a problem - the issue is that number is scoped only to the 3.times
do block. That means that by the time you get to the puts, number is already
out of scope. Thus Ruby looks for the next alternative which is a instance
method by the name of number - not finding one it ends up back at
method_missing and thus the loop of death ensues.

Try this instead

class Roulette
def method_missing(name, *args)
person = name.to_s.capitalize

number = nil #you now have "number" scoped at the method level instead of
the block level

3.times do
number = rand(10) + 1
puts "#{number}..."
end

puts "#{person} got a #{number}"

end
end

Roulette.new.xxx


John


 
7

7stud --

John Feminella wrote in post #983784:
As a rule of thumb, variables exist until you reach the "end" or
closing brace of the innermost block that they're still contained in.
In your case, you have this:


The local variable `number` is created with the value 10 and then
immediately discarded. This happens three times, since the block
executes three times.

The goal of the next statement is to print a local variable called
`number`. But there is no such local variable in this block. So Ruby
rightfully complains that you didn't define it.


Actually, I think the parser determines that 'number' in the line:

puts number

is a method. See this code:

class Dog

def method_missing(name, *args)
puts "*** #{name.to_s} ***"
super
end

def test
3.times do
number = 10
puts number
end

puts number
end
end

Dog.new.test


--output:--
10
10
10
*** number ***

Line 5:in `method_missing': undefined local variable or method `number'
for #<Dog:0x401bf798> (NameError)
from t.rb:14:in `test'
from t.rb:18
 
J

John Feminella

The parser does not think `number` is a method by virtue of writing
"puts number". It tries to invoke a method called number because there
is no local variable named number, because the local variable that you
named `number` is no longer in scope.

To see this for yourself, consider this snippet:

number =3D 10

def number
20
end

puts number
# =3D> 10

Notice Ruby correctly picks the local variable named `number`,
not the method called `number`.

~ jf
--
John Feminella
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: http://stackoverflow.com/users/75170/
 
J

John W Higgins

[Note: parts of this message were removed to make it a legal post.]

John W Higgins wrote in post #984017:

Thanks. I realized my code was just another version of the out of scope
problem discussed earlier.

No problem - some horses just really do need to be beaten well beyond death
:)

John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,602
Members
45,185
Latest member
GluceaReviews

Latest Threads

Top