Smalltalk for the Rubyist
This blog post was written a long time ago and may not reflect my current opinion or might be technically out of date. Read with a grain of salt.
Written on December 9, 2011.
After my previous post about the Pharo ecosystem, some people asked me more about a comparison of Smalltalk and Ruby. And how a Rubyist could leverage his knowledge when learning Smalltalk.
The two languages are class based, dynamic and their supporters like their clean and easy syntax. Actually, Smalltalk is sometimes considered as one of the father of Ruby. They share quite a lot and most of the patterns used in one can be easily expressed in the other.
This post does not cover the basic syntax of Smalltalk. If you want to learn it (15 minutes max), wikipedia should be enough.
Ruby comes in different flavors: MRI, YARV, Rubinius, JRuby, Maglev, etc. So does Smalltalk. The principal difference is that they are no “official” distribution. Every dialect has its own ecosystem and tools. Some are open source, some are proprietary.
Choosing an implementation can be a quite challenging task. If you want to go the open source way:
- Squeak, the most famous implementation. The project has quite a long history. The development seems to have slowed down a bit 3-4 years ago but Squeakers are working hard now.
- Pharo, a fork of Squeak. The goal of the Pharoers is to produce a clean and industry-capable Smalltalk. It all started when some people were really pissed off by the inaction of the Squeak community. Backward compatibility was a pretext for doing nothing. Pharo moves fast and does not aim to stay backward compatible with Squeak. Many projects still runs on the two without a itch though.
- GNU Smalltalk, an alien implementation. You can use your favorite text editor with it. It is a clean implementation but it maybe misses a complete environment.
Gemstone is not only a Smalltalk implementation but also an extremly scalable object-database. Actually Maglev is a Gemstone based products. If you’re serious about Ruby, you should definitely give Maglev a look.
My favorite implementation is Pharo. I like the energy in the community and its direction. It is for me the best bet for the future. It very similar to squeak but this screenshot of the main menu is enough to convince me.
You can follow this thread on stackoverflow to get the opinions of others.
Here comes the biggest problem when learning Smalltalk. That’s where people usually get lost. Smalltalk code does not lie on a plain text file. There are literally no “code time”, it’s always runtime. It would be like coding in an IRB session. You manipulate objects all the time. Consequences ?
- You can inspect object in live. You are working with a webservice and want to inspect the answer? Just inspect the response.
- Change values on the fly. You wanna know what happens if that variable is
5? Change its value to see what happens.
- You can actually code in the debugger. The debugger (or a stacktrace) is not an analysis tool anymore. You can actually code in it. A method is missing? Oops. Create it on the fly and continue the execution from where it failed.
- Fast tests, all the time. Corey Haines teaches you how to get fast tests in rails. You do not need this in Smalltalk as your web/test/whatever framework are already loaded. Of course, if your tests starts to rely on external depencies (disk/network/etc) without mocking, they’ll get slow. No surprises.
Actually some tools are starting to appear in Ruby. Pry is pretty damn cool Ruby tool. Once you’ll get used to Smalltalk environments you’ll want more.
When you load a library in your image, it lies next to your code. You can then read it, inspect it, put breakpoint in it and do whatever you want with it.
An image contains your code and all the libraries you want. It acts as a container and is completely independent from other images.
Metaprogramming, Object and Classes
Okay, that one is tricky. What do you expect from meta-programming?
- Adding methods on runtime? You are already in runtime.
method_missing in Ruby,
doesNotUnderstand must be used carefully. The usual advice applies in Smalltalk.
Actually defining a class in Smalltalk is just sending a message (“calling a method” in Smalltalk jargon) to the class
Object. Adding a method is also a matter of sending a message to define it. The only difference is that you use tools to do it. Remember, it’s runtime and your environment is the running your code. That living environment comes with great responsibilities. If you try something along
Object := nil I guess you’re a footing yourself in the foot.
If you want to learn more about the Smalltalk object system, I warmly recommend the chapter 13 of the Pharo By Example free book. If you don’t know that much about Ruby’s object system, I recommend the Dave Thomas presentation at Scotland on Rails 2009.
Methods need explicit returns (with
^). If omitted, the method will return self.
You get implicit returns for blocks: the value of the last instruction is the the value returned by the block. If you return (with
^) inside a block, it is a return value for the method.
Methods name and variables are spelled in CamelCase. Abbreviations are usually avoided. Smalltalk uses keyword based method name (as in Objective-C). Many Ruby libraries/framework mimic this by passing an hash as argument.
The tabs vs. spaces does not exist in the Smalltalk community. In every tool, press
Tab to indent and you’re done.
As usual, just keep the global syntax style of the project you’re working on.
Be careful when using cascades, a common is mistake is the following:
programmingLanguages := OrderedCollection new add: 'Ruby'; add: 'Java'; add: 'Haskell'.
In the end of the execution, programmingLanguages will be the String
Haskell. That’s because the method
add: returns its argument, not
self. To prevent this, send
yourself at the end of the cascade:
programmingLanguages := OrderedCollection new add: 'Ruby'; add: 'Java'; add: 'Haskell'; yourself.
Another trick of the the language is the evaluation order:
3 + 4 * 5 #=> 35 and not 23
Evaluation is done from left to right. Mathematical order is not preserved. Indeed,
* are simple methods. Smalltalk does not even know (and does not care) that it is executing mathematical instructions. You must use parenthesis to express precedence:
3 + ( 4 * 5 ) #=> 23
My previous post will explain you how to version Smalltalk code. Do not expect
Subversion (although they can be used as backends for Monticello).