I am trying to deal with a very weird (at least to me) situation in Ruby. My code is the following:
class ScopeTest
attr_accessor :flag
def flagtest
puts "SELF: " + self.flag.to_s
puts "INST: " + flag.to_s
if flag == 1
flag = 0
puts "SELF: " + self.flag.to_s
puts "INST: " + flag.to_s
self.flag = 0
puts "SELF: " + self.flag.to_s
puts "INST: " + flag.to_s
flagtest
else
puts "SELF: " + self.flag.to_s
puts "INST: " + flag.to_s
end
end
end
st = ScopeTest.new
st.flag = 1
st.flagtest
And the output is the following:
SELF: 1
INST: 1
SELF: 1
INST: 0
SELF: 0
INST: 0
SELF: 0
INST: 0
SELF: 0
INST:
What's weird is that the flag
variable is nil
the last time I print it (inside the else
) but 0
straight before that (before the if...else
in the flagtest method)?
When I remove a few lines of code, everything seems back to normal as the following code:
class ScopeTest
attr_accessor :flag
def flagtest
puts "SELF: " + self.flag.to_s
puts "INST: " + flag.to_s
if flag == 1
self.flag = 0
puts "SELF: " + self.flag.to_s
puts "INST: " + flag.to_s
flagtest
else
puts "SELF: " + self.flag.to_s
puts "INST: " + flag.to_s
end
end
end
st = ScopeTest.new
st.flag = 1
st.flagtest
gives the following output:
SELF: 1
INST: 1
SELF: 0
INST: 0
SELF: 0
INST: 0
SELF: 0
INST: 0
Any clues as to what and why is happening?
It's because you have assignment to a local variable, flag = 0
. IIRC, local variables are created at parse time and are scoped to the method. They are initialized with nil
by default. So, in your then
clause you assign it a value, before it is accessed. But when you re-enter the method, you go to else
clause and flag
is left uninitialized (that is, nil
).
class ScopeTest
attr_accessor :flag
def flagtest
# if you comment this line, the method will output 1, 1
# if you don't comment, it will output 1, nil, because the assignment to local variable was never done.
# but local var itself was created.
flag = 3 if false
puts self.flag.inspect
puts flag.inspect
end
end
st = ScopeTest.new
st.flag = 1
st.flagtest
# >> 1
# >> nil
flag = 0
creates a local variable called flag whose scope goes to the end of the method. Any use of flag
that appears lexically after that assignment refers to the local variable. Any previous appearance (as well as any appearance of self.flag
) refers to the getter method.
So the flag
in the else
refers to the local variable. Since the local variable never got a value in the else
-branch, its value is nil
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With