For the sake of completion, an example from the Squeak image:
Integer>>+ aNumber
"Refer to the comment in Number + "
aNumber isInteger ifTrue:
[self negative == aNumber negative
ifTrue: [^ (self digitAdd: aNumber) normalize]
ifFalse: [^ self digitSubtract: aNumber]].
aNumber isFraction ifTrue:
[^Fraction numerator: self * aNumber denominator + aNumber numerator denominator: aNumber denominator].
^ aNumber adaptToInteger: self andSend: #+
This shows:
- that classes work as some kind of 'practical typing', effectively differentiating things that can be summed (see below).
- a case of explicitly checking for Type/Class. Of course, if the parameter is not an Integer or Fraction, and does_not_understand #adaptToInteger:andSend:, it will raise a DNU (doesNotUnderstand see below).
some kind of 'coercion' going on, but not implicitly. The last line:
^aNumber adaptToInteger: self andSend: #+
asks the argument to the method to do the appropriate thing to add himself to an integer. This can involve asking the original receiver to return, say, a version of himself as a Float.
- (doesn't really show, but insinuates) that #+ is defined in more than one class. Operators are defined as regular methods, they're called binary methods. The difference is some Smalltalk dialects limit them up to two chars length, and their precedence.
- an example of dispatching on the type of the receiver and the argument. It uses double dispatch (see 3).
- an explicit check where it's needed. Object can be seen as having types (classes), but variables are not. They just hold references to any object, as Smalltalk is dynamically typed.
This also shows that much of Smalltalk is implemented in Smalltalk itself, so the image is always a good place to look for this kind of things.
About DNU errors, they are actually a bit more involved:
When the search reaches the top class in the inheritance chain (presumably ProtoObject) and the method is not found, a #doesNotUndertand: message is sent to the object, with the message not understood as parameter) in case it wants to handle the miss. If #doesNotUnderstand: is not implemented, the lookup once again climbs up to Object, where its implementation is to throw an error.
Note: I'm not sure about the equivalence between Classes and Types, so I tried to be careful about that point.