A trap to avoid with ruby assignments

Another thing that’s pretty confusing for ruby new comers is the assignment operator (the “=” sign).
When you write something like : my_obj = MyClass.new, the “=” sign does what you think it does. However, when you write : my_obj.yadayada = “123”, it doesn’t (Ruby has a tendency to fool people).

Why is this second form of assignment any different?

In the second example, it seems like we are trying to set the attribute yadayada of my_obj, but that is impossible because ruby doesn’t allow this. As soon as it sees the dot after an object name, it expects to see a method, nothing else. Ruby doesn’t want you to play with the attribute of an object directly, it wants you to call it’s accessor methods.
If that is so, why didn’t Ruby complained when we wrote my_obj.yadayada = “123” ? It is a clear attempt to set an object attribute directly! Hmm, maybe it isn’t. Look closely. As much as it looks like a standard assignment, it is indeed a method call. When you write my_obj.yadayada = “123”, Ruby understands : my_obj.yadayada=(“123”). The “=” sign being the last character of the method name, that is : yadayada=.
If you don’t define the yadayada= method in MyClass, Ruby will complain by raising the following exception :
NoMethodError: undefined method ‘yadayada=’ for #MyClass:0x2c9be70.
As you can see, it is expecting a method, nothing else. That’s why you have to name your attribute writers with a trailing “=” if you want to give the illusion that an assignment occured. As for attribute readers, you have to give them the same name as the real attributes.

class MyClass
  def initialize()
    @yadayada = "initial value" #The real attribute
  end
  #Attribute reader
  def yadayada()
    @yadayada
  end
  #Attribute writer
  def yadayada=(some_value)
    @yadayada=some_value #real assignment! no more fooling
  end
end
#using the class
my_obj=MyClass.new()
puts(my_obj.yadayada) #calls the instance method "yadayada"
my_obj.yadayada = "some value" #calls the instance method "yadayada="

Congrats, mister Copperfield, the illusion is perfect! I’d like to point out that if the only thing your accessors are doing is to respectively get and set the real attribute value, you could use one or more of the following helpers at the beginning of your class : attr_reader, attr_writer and attr_accessor. For example, if you write attr_accessor :yadayada, your two accessors for the yadayada attribute will be created automatically for you. If you only want an attribute reader, use attr_reader. If you only want an attribute writer, use attr_writer.

A last twisted case

What if we write : my_hash[:my_key] = “some value” ?
It looks like a “real” assignment don’t you think? How can a method be named “[:my_key]=” ? It doesn’t make any sense. Well, I know… but ruby did something funky once again.
Question : What is the method name in my_hash[:my_key] = “some value” ?
Answer : []=
No kidding, []= is an instance method in the Hash class.
If Ruby was evil, it would force us to write the last statement in the following way : my_hash.[]=(:my_key,”some value”). We would all become completely crazy and it would be dangerous to our health. Fortunately, Ruby isn’t evil, it is our friend. It let us refer to our hash in a comprehensive manner so we don’t lose our mind. Then, it does some tricks we don’t want to know in the background that will transform :

my_hash[:my_key] = "some value"

to

my_hash.[]=(:my_key,"some value")

Phew… you won’t have to use the 2nd form, ever. I wonder what would people say about ruby if it was the case. But just in case you’re curious or doubtful, run IRB and write the following :

apple = {:color => "green", :variety => "granny smith"}
apple.[]=(:color,"red")
apple.inspect

10 thoughts on “A trap to avoid with ruby assignments

  1. The difference between the first and second cases is that instance variables in Ruby are essentially protected by default. There is no trap; assignment in Ruby is always performed using a method call.

  2. Ben,
    I’m not sure to understand what you mean. if I write obj = MyClass.new, the equal sign isn’t “bound” to any method name. This is what i was talking about.

  3. Hi, I’m currently learning Ruby ( and, sure, Rails) and found your posts very interesting. I’m start to understanding the whole thing behind Ruby and all beauty of the language 🙂
    I understood why I use symbols all the times in Rails..
    Tks

  4. My mistake. For the longest time, I’d assumed that every action boiled down to a method call in Ruby. Guess not:
    $ irb
    irb> hello = 'ted'
    => 'ted'
    irb> def hello; 'bob'; end
    => nil
    irb> hello
    => 'ted'
    irb> hello()
    => 'bob'

  5. There’s one more way to create readers and writers, somewhere in between writing your own and calling attr_accessor or attr_reader: attr. attr takes a Symbol and an optional Boolean. The Symbol is the name of the accessor and the Boolean determines whether a writer is also created. The created accessor methods basically look exactly like the ones you demonstrated.
    attr_accessor and attr_reader take any number of Symbols and basically just call attr(:sym, true) or attr(:sym) for each one.
    However, I have no idea why and when one would actually want to use attr over attr_accessor.
    jwm

  6. Thanks everyone for your comments, i really appreciate. Hugo, your comment made my day. Knowing that some people appreciate my work means a lot to me. It’s cool to see your interest in the language. Ruby is one wild beast but to me it’s the most interesting and elegant language out there.
    Jörg, I didn’t know about the attr keyword. Thanks for the input! Like you said however, I don’t know why one would use it instead of the other more “verbose” helpers…
    Is it some deprecated feature?

  7. Cool one! I already *supposedly* knew this but reading it again it helped clarifying and settling the concepts. Coming from a non-ruby background, I always forget how the attributes and accessors work in ruby 😀

  8. you are truly a just right webmaster. The web site loading speed is incredible.
    It sort of feels that you’re doing any unique trick.
    Moreover, The contents are masterpiece. you’ve
    done a excellent task on this subject!

Leave a Reply

Your email address will not be published. Required fields are marked *