Skip to content

Instantly share code, notes, and snippets.

@avand
Created June 20, 2012 00:18
Show Gist options
  • Save avand/2957288 to your computer and use it in GitHub Desktop.
Save avand/2957288 to your computer and use it in GitHub Desktop.
class Car
attr_accessor :brand
def a
if false
# brand = nil
else
brand
end
end
def b
if false
brand = nil
else
brand
end
end
end
car = Car.new
car.brand = "Subaru"
puts car.a # => "Subaru"
puts car.b # => nil (WTF?!)
@jdfrens
Copy link

jdfrens commented Jun 20, 2012

The brand = nil is seen as a local variable definition which activates it for the else (setting it to nil):

irb(main):015:0> if false ; foo = 5 ; else foo end
=> nil
irb(main):016:0> if false ;            ; else crap end
NameError: undefined local variable or method `crap' for main:Object
     from (irb):16

@joelash
Copy link

joelash commented Jun 21, 2012

It's not just the brand = nil causing a local variable definition at parse time, that's causing your confusion however.

Building out our example more may provide you another piece of the puzzle that you're missing.

class Car 
  attr_accessor :brand

  def a
    if false
      # brand = nil
    else
      brand
    end 
  end 

  def b
    if false
      brand = nil 
    else
      brand
    end 
  end 

  def c
    brand = 'Fiat'
  end 

  def d
    self.brand = 'Pontiac'                                                                                                                                                                               
  end 
end

car          = Car.new
car.brand = "Subaru"

puts car.a # => "Subaru"
puts car.b # => nil

puts car.c # => "Fiat" (really only for the "side effect")
puts car.a # =>  "Subaru" (see what happened there?)

puts car.d # => "Pontiac" (yet again, only for the side effect)
puts car.a # => "Pontiac"

The attr_accessor :brand is being defined on the Car's metaclass, causing you to technically need to alter it by calling self.brand= and not just brand= which is seen as a local variable definition. Note that self.brand= is very different than self.class.brand= which would be calling a class method not an instance method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment