Ruby 101: Methods and messages

Posted by jeff Wednesday, August 15, 2007 15:26:00 GMT

I hope that someone gets my
I hope that someone gets my
I hope that someone gets my
Message in a bottle

The Police

Got a great question from Scott Porad the other day, asking about this line of code that’s produced by the scaffold generator in Rails 1.2 (note, in Scott’s application, his model is called content):

My question has to do with this line:

<td ><%= h content.send(column.name) %></ td>

What exactly is content.send(column.name) doing?

We all know that Ruby is an object-oriented language. However, many of us who are accustomed to .NET or Java may not realize that Ruby is really based on message passing, not method calling. The difference is so subtle that you can start using Ruby right away, and get pretty far, without ever knowing the difference. But this line in the scaffold code takes advantage of message passing to great effect.

When you write a Ruby class and define some methods inside of it, those methods are just predefined responses to certain messages.


    class Thermometer

        def temperature
            75
        end

    end

To think in terms of message passing instead of methods, try to read this code out loud as, “This is class Thermometer. It can respond to a message named ‘temperature’. It will respond with 75 when it receives the message.”

It looks like a method call in your previous favorite language, and the message-calling syntax in Ruby looks like the method-calling syntax in that old language, too:


    t = Thermometer.new
    puts "It is " + t.temperature " + degrees outside." 

When the Ruby interpreter sees t.temperature, it passes the message temperature to the t object. There are actually two ways we could have sent this message to the object. The first is what we did here. But there’s another, more generic way to send a message to an object, and that’s with the send method that’s available to every Ruby object:


    t = Thermometer.new
    puts "It is " + t.send('temperature') " degrees outside." 

Here we sent the message named ‘temperature’ to the object. Since Thermometer has defined a response to the temperature message, Ruby is able to locate that response and execute it.

This means that you can write code that does not know method names a priori. Let’s go back to the scaffold code. When you run script/generate scaffold Product, the generator has no idea what columns your Product table will have. Yet it is able to generate that code that will automatically display all of the data in your table. It’s able to do this by first reflecting on your table for the column names, and then asking your model for the value of the attribute with that same name:


    product.send(column.name)

So in this code, the product object is being passed a message, and it’s using the column name as the name of the message. ActiveRecord responds by returning the value of that column in the database. Beautiful!

In fact, your code can first find out if a given object will respond to a given message with respond_to?:


    t = Thermometer.new
    if t.respond_to? 'temperature'
      puts "Yes, it can tell you the temperature" 
    else
      puts "No, it can not tell you the temperature" 
     end

Today we looked at one way an object can respond to this message: providing a predefined response to a specific, named message. There’s another way to respond to messages, without writing def blocks at all.

But as Alton Brown likes to say, that’s another show.

Questions? Clear as mud? Drop me a comment.
Ready to learn more? Sign up now for Essential Rails

Comments

Leave a response

  1. Todd   August 15, 2007 @ 06:46 PM

    Wow! really? I didn't know at all. Thanks for a great article.

  2. Matt Blodgett   August 15, 2007 @ 06:56 PM

    Ruby continues to blow my mind. Great post.

  3. Pratik   August 15, 2007 @ 08:49 PM

    Sweet post :-)

    You might wanna put a lil mention somwhere that send() will allow you to call private methods too. Which is something very likely to be changed in ruby 2.0 for cases where you call send() with a receiver.

  4. Cameron Singe   August 15, 2007 @ 11:24 PM

    I love the send method, you can really current down on the code and it also helps keeping away from dirty eval statements.

  5. Larry Kluger   August 17, 2007 @ 12:15 AM

    Be careful when using respond_to? in hot sections of production code--it's slooow. Especially for ActiveRecord models.

  6. John Topley   August 17, 2007 @ 08:14 AM

    Isn't the distinction between message sending and method calling a semantic one? Language A could use message sending and Language B could use method calling but internally they might both implement method dispatch in the same manner.

    Undoubtedly the send method is a powerful and useful tool but I see no logical reason why Java (for example) couldn't have an "invoke" method on Object that does the same thing. It's just not architected to be that useful.

  7. Jeremy Weiskotten   August 17, 2007 @ 02:05 PM

    @John: You can do the equivalent in Java using the Reflection API. You can get pretty close to the brevity in Ruby if you use a wrapper like Apache Commons BeanUtils - http://commons.apache.org/beanutils/apidocs/

  8. John Topley   August 17, 2007 @ 02:37 PM

    @Jeremy: Yes, I'm aware of that, thanks. I wasn't looking to actually do it in Java, I was trying to make the point that the difference between whether you think of objects as sending messages to one another or invoking methods on each other is semantic rather than technical. Or perhaps I'm completely wrong and it runs deeper than that...?

  9. Jeff   August 17, 2007 @ 02:42 PM

    @John and @Jeremy: Actually, the difference is important, and it's one of the differences between a static language like Java/C# versus a dynamic language like Ruby. Even with reflection, the list of methods is fixed at compile time.

    In Ruby objects can respond to messages without having predefined methods for them. In other words, without having a method dispatch table entry for your message. This is what method_missing is all about, and perhaps I'll follow up soon with an article about how that works.

  10. John Topley   August 17, 2007 @ 03:08 PM

    Thanks Jeff - makes sense. Stupidly, I'd forgotten that Ruby lets you send messages to objects where the message doesn't exist until runtime. A good example being ActiveRecord's dynamic finders.

  11. Jeff   August 17, 2007 @ 03:56 PM

    A good example being ActiveRecord's dynamic finders.

    Exactly! And my hunch is that's also where the performance problems are that Larry was referring to.

  12. Pratik   August 18, 2007 @ 06:12 PM

    @Jeff : Well, that hunch is certainly not correct.

  13. Shadowfiend   August 18, 2007 @ 08:21 PM

    Also worth mentioning is that send also exists as send, and only send (along with id_) will print warnings when you're trying to undefine them (and $VERBOSE is on). So it's likely safer to use _send than it is to use just plain send if you're dealing with objects that may be modified beyond what you've done.

  14. Shadowfiend   August 18, 2007 @ 08:22 PM

    Er... That was send...

  15. Shadowfiend   August 18, 2007 @ 08:23 PM

    facepalm... Fine. That was underscore-underscore-send-underscore-underscore...

  16. Jonas F.   August 19, 2007 @ 08:50 PM

    It's a shame the whole world's still using java..

  17. Alex Egg   August 22, 2007 @ 07:41 PM

    Thanks, this is great from a C# developer's perspective.

  18. Guequillitila   October 04, 2007 @ 06:23 AM

    http://firsthotsex.net/best/nymphet-ukrainian-underage.html nymphet ukrainian underage

  19. Oxinkexillamn   October 30, 2007 @ 08:07 AM

    http://movie-hentai.net/bigboard/ayami-kojima-manga.html ayami kojima manga ayanami hentai pic rei http://movie-hentai.net/bigboard/ayanami-hentai-pic-rei.html ayanami hentai pic rei ayanami hentai rei http://movie-hentai.net/bigboard/ayanami-hentai-rei.html ayanami hentai rei ayanami hentai rey http://movie-hentai.net/bigboard/ayanami-hentai-rey.html ayanami hentai rey ayanami manga http://movie-hentai.net/bigboard/ayanami-manga.html ayanami manga ayanami manga rei

  20. Sunil   November 27, 2007 @ 06:33 AM

    Sir !!! Hats off to you and your way of explaining things in such a lucid language. I am a student of ruby and rails ...and your articles make us Rich ! really !!

    Thanks again,

    Warm regards

    Sunil

  21. Maggie Walls   March 24, 2008 @ 05:16 PM

    sleepingly underclassman hederaceous castanet deacidification immure soapmaker crouchingly Bathurst Macquarie Rover Crew http://phact.org/e/z/freewire.htm