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.

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 :

to

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 :

  • http://www.benlog.org Ben

    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.

  • http://www.rubyfleebie.com Frank

    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.

  • Hugo

    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

  • http://www.benlog.org Ben

    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'

  • Jörg W Mittag

    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

  • http://www.rubyfleebie.com Frank

    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?

  • http://www.soledadpenades.com sole

    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 :D

  • http://hstpahh.com/svisbo.html Judith Blackburn

    hi
    zydprbknhvb02gn4
    good luck

  • http://blog.libero.it/wyeseniaelena/12761482.html Sul retro del tovagliolo. Come risolvere problemi e vendere idee con le immagini pdf

    Awesome post.

  • http://www.chukono1.com/userinfo.php?uid=299822 it

    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!