Friday, August 03, 2007

Ruby versus Smalltalk

Is Ruby a lesser Smalltalk? Well I use to think so, but now, after using Ruby for a while, I'm not so sure. Well Smalltalk definitely excels when it comes to tools, but as with Java, Ruby's increasing success will mean that better Ruby tools are sure to appear soon.

The reason why I'm not so sure is the ability to create macros in Ruby, in much the same way you would with Lisp. For those that don't know, a macro function is a function that writes functions, so code that writes code. Rails uses this technique all over the place. For example the famous scaffold method is a macro. Your Controller class writes itself when it gets defined at runtime. AFAIK this just isn't possible in Smalltalk or is it? Why is this important? Because you can add new control structures to your language, extending the language and creating DSLs in much the same way you can with Lisp macros.

It looks as though Ruby is a true successor to Lisp in a way that Smalltalk never has been. Is this true or am I missing something?

7 comments:

Brian T. Rice said...

Smalltalk's grammar doesn't allow you to lexically nest a method definition inside of another method's source, but you can accomplish the same thing by installing a block as a method on a class, or at a more basic level, you can pass a source string to the compiler to define the desired method.

(Due to time constraints, concrete examples left as an exercise to the reader...)

Paul said...

Hi Brian,

I've never tried either of these things, although I sort of knew that you could pass a string to the compiler at runtime in Smalltalk. I guess the Ruby equivalent is eval.

Neither approach sounds very Lispy though. I guess I should try them myself. The thing with Lisp is that second order functions feel very natural. I haven't written any production Smalltalk code, but I get the feeling that second order functions are less common in Smalltalk.

The thing with Ruby (and Lisp I think) is that the program doesn't define itself until runtime. With Smalltalk the program is always running and you extend classes at runtime using the program itself which so happens to have class browsers etc. These tools don't naturally seem to support the idea of a macro. So as it stands in Smalltalk you can add class methods or instance methods, but you can't add a macro.

Maybe this explains why second order functions are less common in Smalltalk? The thing with Smalltalk though is that you probably could extend the class browser to support macros. The only question left in my mind is when Smalltalk macros should/would get executed? One idea that comes to mind is adding macro calls to the message that creates the class. So by saving the class definition, macros get executed and methods (code) gets created.

I guess its the "define and run" all at the same time idea which is the thing that makes Ruby closer to Lisp. As you can probably tell my knowledge is sketchy in parts, so I'm happy for anyone to confirm or deny my thoughts.

Thanks for the comment,

Paul.

Brian T. Rice said...

I should add that I'm an avid Common Lisp user, and I think that what I've cited is certainly lispy enough, more so than Ruby's grammatically-suspect hard-wired support.

Paul said...

Hi Brian,

I think I know what you mean when you talk about Ruby's grammar :^)

Having said this, I'm even getting use to all the grammatical inconsistency in Ruby too. I think Ruby calls for a good coding standard and fortunately the Rails guys are consistent in the way they use underscores parenthesis, capitalisation, etc.

The Lispyness I referred to is the way in which a Ruby program is read prior to being evaluated much like Lisp. Here is a blog by someone more qualified then me:

http://www.randomhacks.net/articles/2005/12/03/why-ruby-is-an-acceptable-lisp

I particularly like the DSL stuff like the example with ActiveRecord and :has_many.

Don't get me wrong, I really do feel that there is something magical about the fact that your program is always alive in Smalltalk, and you just add classes, methods etc to your image whilst its' still running.

From the first moment I played with Smalltalk, I thought that this has got to be the way programming should be.

I do find it interesting though that Ruby has a few tricks of its own.

Maybe you'll find the time to blog on the Lispyness of Smalltalk. Like I say my Smalltalk experience is limited (basically stuff I've written for fun by myself).

It would be nice to see what Smalltalk can do when it comes to emulating the power of Lisp.

I like both languages (all three in fact, Smalltalk, Ruby and Lisp), although Smalltalk is my first love :^) It's just interesting to contrast and compare them.

Steve said...

Hi Paul, you are seriously missing something

Pascal said...

I think your confusing "second-order function" and macro.

2nd order function are function that take as argument other function and/or return function.

Macro are compile time expansion that generate code for the compiler.

Macro are not available in Smalltalk
(the "syntax-less" structure of Lisp/Scheme make them perfect for macro!)

But, if I remember correctly, you could do higher order function in Smalltalk: they can take code block as input. Not sure if they can return a code block.

Brgds.

Paul Beckford said...

Thanks Pascal. Yes that is what I meant. Thanks for the correction, I've updated the post.