-
-
Save sdball/5162135 to your computer and use it in GitHub Desktop.
class NilWhatAreYouDoingStahp | |
attr_accessor :not_nil | |
def initialize | |
@not_nil = "I'm not nil! I'm a value!" | |
end | |
def wat | |
if not_nil.nil? | |
not_nil = "Ok, now I'm not nil." | |
end | |
not_nil | |
end | |
def omglol | |
not_nil | |
end | |
end | |
stahp = NilWhatAreYouDoingStahp.new | |
stahp.wat # => nil | |
stahp.omglol # => "I'm not nil! I'm a value!" |
Thanks for turning it into a fun puzzle instead of a head-banging-against-keyboard piece of code :-)
from @olery instead of @Sparkboxx, since I somehow can't swap the Gist page back to @Sparkboxx instead of the organization account
Although confusing at first this makes sense once you become familiar with the MRI internals (which is a bit of a sad requirement). This is because the Ruby parser pre scans scopes for the assignments of variables and processes them up to a certain extend. It doesn't assign any values yet though, instead it sets them to their default values (NilClass in this case).
In this particular bit of code Ruby sees that there's a possible local variable assignment in Foo#wat
and as such pre-creates it. You can test this by adding p local_variables
between lines 8 and 9 and you'll see that it displays [:not_nil]
.
Normally this wouldn't be an issue but since your local variable and the getter method are named the same way you get a conflict. In Ruby local variables have precedence over methods in the same scope. As a result this method will return the value of the local variable and not the getter.
To work around this issue one would have to use the following code:
class NilWhatAreYouDoingStahp
attr_accessor :not_nil
def initialize
@not_nil = "I'm not nil! I'm a value!"
end
def wat
# note the use of "self.", it's important in this case.
if self.not_nil.nil?
self.not_nil = "Ok, now I'm not nil."
end
self.not_nil
end
def omglol
not_nil
end
end
stahp = NilWhatAreYouDoingStahp.new
p stahp.wat
stahp.omglol
An even better alternative would be to use local variables with a different name.
Spot on! Another fun way to present this puzzle is to say that adding five characters makes the code work as expected. That's almost a giveaway though.
This comes to us from @Sparkboxx btw!