Smalltalk for the Rubyist
Written on December 9 2011.
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.
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.
Implementations
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.
- Amber, a smalltalk that compiles to Javascript. Pretty young but already impressive. It can be used with Node.js or in the browser.
I’m not really interested in proprietary implementations but there are three big players in that field: Cincom Smalltalk, VA Smalltalk, Gemstone/S.
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.
The Environment
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
instead of5
? 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.
- Handle
method_missing
? WelcomedoesNotUnderstand
.
As 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.
Returns
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.
Syntax Convention
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.
Usual suspects
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, +
and *
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</pre></div>
Version Control
My previous post will
explain you how to version Smalltalk code. Do not expect Git
, Mercurial
or
Subversion
(although they can be used as backends for Monticello).
Conclusion
Once again, this post is inspired by someone else doing the same for Javascript (thanks Greg Spurrier for the link). The Squeak by Example or Pharo By Example books are worth to read. Beware that the tools described in the book are sometimes outdated but the principles are still perfectly valid.