lördag, september 16, 2006

The limits of power: What Lisp can do but Ruby can't

I've for a long time been thinking about where Ruby's limits are, compared to Lisp. As I see Lisp as the ultimate power, this is mostly about trying to gauge the power of Ruby, in a very unscientific, highly opinionated and very subjective way. I talked some with Jim Weirich, _why, Charles and few others about this in London which started me thinking again. Actually, I've only find one macrotype that really isn't possible in Ruby. And it's only impossible if you require that the syntax doesn't change.

First, required reading for this post is Why Ruby is an acceptable Lisp by Erich Kidd. I happen to agree with this, in almost all cases, but there are a few corner cases where Lisp is just more convenient. As a first example, let's take a typical AOP task. I want to define a method to execute before the method foo. The definition of foo is like this:
def foo(arg1, arg2, arg3)
do.something {}
end
And my before-advice, which I would really like to be able to write like this:
defbefore foo(arg1, *args)
puts "before foo with first arg #{arg1}"
end
This isn't possible. The closest I really can come up with is this:
defbefore :foo do |arg1, *args|
puts "before foo with first arg #{arg1}"
end
This isn't so bad, of course. But it puts a disconnect between the language and your extensions. The most powerful macro facility is invisible to the programmer. There should be no division between how keywords work and how macros could function. To take another example of this, take the classical pattern for logging:
logger.debug{"baz: #{expensive_formatting_operation(baz)}"}
where the block is used to avoid calling expensive_formatting_operation if debug-logging isn't turned on. This is neat. But it isn't neat enough. I would like to be able to write
logger.debug "baz: #{expensive_formatting_operation(baz)}"
and avoid having expensive_formatting_operation run if debug-logging is off. In the general case this isn't possible in Ruby. There is parts of the execution process that there are no hooks into.

Of course, as I said in the beginning, this doesn't really matter in most cases. In almost all cases the convenience of Ruby's powerful syntax, emerging libraries and great frameworks is what you get for that small power-tradeoff. But even so, I would like to be able to go that extra distance in power. Could something like this ever be possible in a language that has syntax? I'm not sure. Maybe if there was a well defined way that Ruby translates into something that resembles S-expressions. In that case you could have macros that work on these internal concepts instead of on pure Ruby-syntax. Of course, this means a division into two languages, but it would give that extra power.

1 kommentar:

Ryan Bates sa...

The idea of before and after method definitions is mentioned in Matz's Wild and Weird Ideas presentation. Maybe it will be added someday. :)