This post originated from an RSS feed registered with Ruby Buzz
by Michael Neumann.
Original Post: Python Decorators
Feed Title: Mike's Weblog
Feed URL: http://www.ntecs.de/blog-old/index.rss?cat=ruby&count=7
Feed Description: Blogging about Ruby and other interesting stuff.
I read about Python
Decorators on Lambda-the-Ultimate. They will be part of Python 2.4.
But, was it really worth to add special syntax for something that can be
done without problems in a different way? Isn't Python breaking it's own
principle "There's only one way to do it"? Will Python become a
second Perl? Which so-called "feature" will be added next? Don't
get me wrong, Python is a valuable language!
The Ruby language instead is pretty constant since it's very beginnings
(version 1.0 of December 1996). There are no visible changes in the
language (but in the library!) except the introduction of class-variables
in 1.4 (or was it 1.6?).
Decorators in Python
Instead of:
def f(...)
...
f = synchronize(f)
you can now write:
@synchronize
def f(...)
...
The part after the at-sign is simply a function (synchronize is
our case).
Decorators in Ruby
def f
...
end
synchronize :f
That's pretty the same as the first Python example shown above. But can we
simulate the second Python example in Ruby? Yes we can! We could do this in
pure Ruby, but that would be a bit more advanced. Therefore I'll show you
how to do it with a minor change to the Ruby interpreter. Minor means that
the change does not break any existing code and that only one line
needs to be changed:
--- eval.c 2 Aug 2004 08:52:53 -0000 1.686
+++ eval.c 16 Aug 2004 12:52:28 -0000
@@ -3701,7 +3701,7 @@
rb_add_method(rb_singleton_class(ruby_class),
node->nd_mid, defn, NOEX_PUBLIC);
}
- result = Qnil;
+ result = ID2SYM(node->nd_mid);
}
break;
With this patch applied, a method definition will return the method name as
symbol. Let's try this:
x =
def f
end
p x # => :f
Now we can "simulate" the second Python example in Ruby:
synchronize def f
...
end
# or with the decorator on a separate line
synchronize \
def f
...
end
Note that the backslash after the synchronize in the second part
of the example is neccessary! This tells Ruby that the argument is
on the next line.
And we can even cascade "decorators":
private memoize synchronize \
def f
...
end
Of course this only works if each involved "decorator" method
passes the method-id through.