tisdag, augusti 14, 2007

New double-operators in Ruby

So, I had a great time at the London RUG tonight, and Jay Phillips managed to show me two really neat Ruby tricks. The first one is in this post, and the next one is about the second.

Now, Ruby has a limited amount of operator overloading, but that is in most cases limited by what is predefined. There is actually a category of operators that are not available be the regular syntax, but that can still be created. I'm talking about almost all the regular single operators followed by either a plus sign or a minus sign.

Right now, I don't have a perfect example of where this is useful, but I guess someone will come up with it. You can use it in all cases where you want to be able to use stuff like binary ++, binary --, /-, *+, *-, %-, %+, %^, and so forth.

This trick makes use of the parsing of unary operators combined with binary operators. So, for example, this code:
module FixProxy; end

class String
def +@
extend FixProxy
end
alias __old_plus +
def +(val)
if val.kind_of?(FixProxy)
__old_plus(" BAR " << val)
else
__old_plus(val)
end
end
end

puts("Foo" ++ "Baz")
will actually output "Foo BAR Baz".

I'm pretty certain someone kind find a good use for it.

4 kommentarer:

Anonym sa...

You have to be a little more careful than that. Given your implementation above:

  suffix = "suffix"
  
  "foo" ++ suffix # => foo BAR suffix
  "bar" + suffix # => foo BAR suffix

which probably isn't what you want.

  def +@
    dup.extend FixProxy
  end

is probably safer, but if you need to call any mutators on suffix it won't quite behave correctly. In that case you'll need to turn your proxy into a decorator with slightly more complex behaviour.

But you knew that, I'm sure.

Ola Bini sa...

You are absolutely right. And no, I didn't think about this when I wrote the post, so thanks for the clarification. =)

I just wanted to say something about the concept. I'm not even sure I like it that much, especially since it will make things a little complicated in the real life, as you say.

Anonym sa...

It's the sort of thing I wouldn't ever want to see in the body of general ruby code.

However, it's an awfully useful technique when you're attempting to make a block scoped little language (RSpec's probably the best current example of what I mean).

Daniel Berger sa...

It would be better to tweak the parser I would think.