Send my love to Ruby II

In the last post, we saw a nice use case for the #send method. Now, we’ll see some coolness that Rubinius adds. First, some code:


class Apple
  def seed
  end
end

a = Apple.new

a.send :seed
a.__send__ :seed

Now, with the convenient and useful describe facility of the Rubinius compiler, we can see something interesting:


$ shotgun/rubinius describe send.rb
Path: send.rb
Size: 79 bytes

Sexp:
  [:block, 
  [:newline, 1, "(eval)", 
    [:class, [:colon2, :Apple], nil, 
      [:scope, 
        [:newline, 2, "(eval)", set_local_fp 1 ; local a

---- snip ----

pop
#line 8
push_literal 1
get_local_fp 1 ; local a
send send 1
pop
#line 9
get_local_fp 1 ; local a
push nil
push_literal 2
dup
is_symbol
git send_lbl1
send to_sym 0
send_lbl1:
push 0
set_args
send_off_stack
pop
push true
ret

---- snip ----

I’ve truncated that output, but feel free to run this at home. (There’s no long lasting side effects other than an itching desire to contribute to the Rubinius project.) If you correlate the assembly with the line numbers in the source, you’ll notice that the two sends are not turning out to be the same. That’s right. We have a special, and fast, __send__ operation.

The #send method is a highly useful bit of Ruby. Unfortunately, there’s some concern that using it can hurt performance. Well, with Rubinius you can have your send and use it, too.

6 Responses to “Send my love to Ruby II”

  1. Dr Nic Says:

    More “look how cool Rubinius is” posts are always a good thing :)

  2. Ummm Says:

    I’m really not getting this… so why have a special semi-hidden send method that’s faster? Why not make the regular send method faster? Is there anything semantically different between the two?

    So you introduce a speciel send method that’s faster in Rubinius and people will start using it… then when they need to port their code to JRuby or MRI (now with YARV!) they’ll need to either change their code or alias the send to send.

  3. Brian Says:

    Ummm,

    There’s nothing semi-hidden about send. MRI has it. Basically, it’s there so you can use send in your own code. So feel free to use it.

    This whole argument that “people will get bad habits using Rubinius” is just silly. First, you won’t have any compelling reason to use another C-ish (MRI, YARV) implementation over Rubinius. Second, we’re not introducing any incompatibilities with Ruby core classes.

    Finally, why have this? First, because we can. Second, because this is optimized for when send is passed a symbol. That’s a reasonable optimization that has no semantic impact on the code that is written.

    Rubinius will ultimately have many, many optimizations underneath. By definition those do not change the semantics of the programs. They just make it run faster. Don’t like it? Well, now you have choices. :)

  4. Brian Says:

    Damn textile. The first send is

    
    __send__
    
  5. Ummm Says:

    Ah, my post lost the underbars around send as well… So it doesn’t make as much sense and now I can understand your response…

    I’m not saying that Rubinius shouldn’t have some of it’s own optimizations… I didn’t understand from your post that “underbar underbar send underbar underbar” (OK, I can’t figure out how to escape the underbar) was optimised to take a symbol only (where as the regular send can take either a symbol or a string, correct?)

    Still, if I move code that uses this “underbar underbar send underbar underbar” over to run on MRI or JRuby I’ll have to create an alias for it that calls the traditional send method. It’s not the end of the world, but if there are a lot of these kinds of issues it could make it harder to switch back and forth – and while I think Rubinius is the bomb and will eventually be the only ruby implementation, I know that for a while people will have to deploy code in places where they might only have MRI even if only for reasons of policy.

  6. Brian Says:

    No alias is necessary. __send__ exists in MRI. It is ugly and most likely will not be used in application code. We chose to implement it with this optimization for use in library code. Our aim is to make Ruby fast, so you write great code and care less about optimization, which is an art and often not necessary.

Sorry, comments are closed for this article.