What are the key differences between OO in Smalltalk and Java?
Please note that I am a Java programmer trying to expand his horizons by exploring Smalltalk. Currently I know almost nothing about Smalltalk except that it's purer than Java. Therefore I'll prefer the answer that shows how various Java concepts map to corresponding Smalltalk concepts and then introduces the Smalltalk concepts that don't exist in Java at all.
Smalltalk uses message passing, not method invocation. The distinction is subtle, but enormously powerful.
Some terminology: Given foo bar: baz
, #bar:
is a selector, foo is the receiver of a message called #bar:
(the # indicates a symbol, much like Common Lisp would say 'bar
(or even more appropriately, :bar
)), and baz
is an argument or parameter. When the line's executed, foo
is sent the message #:bar:
with argument baz
. So far, it's pretty normal. In Java it would look like foo.bar(baz);
.
In Java, the runtime system would figure out foo
's actual type, find the most appropriate method, and run it.
Things look almost the same in Smalltalk. When you send an object a message, it searches in its method dictionary for a method whose name matches that of the selector of the message. If it can't find one, it searches in its superclass' method dictionary, and so on. Pretty normal stuff.
If it can't find any matching method, it sends itself the #doesNotUnderstand:
message, with the original message as a parameter. (Yes, a message send is an object.) But #doesNotUnderstand:
is also just a method. You can override it.
For instance, you can have an object that responds to some set of messages while forwarding any other messages it receives to some delegate object. Override #doesNotUnderstand:
and hey presto, you have a proxy that will need no maintenance to keep its protocol in sync with the delegate.
No, I'm not joking. Smalltalk's entire grammar's maybe 15 lines long. The JLS is... not. Why care? A simple syntax makes it simple to tear a chunk of code apart. Metaprogramming! Refactoring!
No syntax for:
(n < 3) ifTrue: ['yes'] ifFalse: ['no']
1 to: 10 do: [:i | Transcript show: i asString]
[i := i / 0] ifError: ['oops!']
[i := i / 0] ensure: [stream close]
And notice all those []
s - first-class closures with a clean syntax.