First of all, one must realize that Smalltalk is a purely object oriented language with purely dynamic types. That is to say that the language consists of essentially three things: classes, objects, and messages (self people will claim that having classes makes Smalltalk not pure but you get the idea). Given an object, a message sent to that object (potentially having other objects as arguments) will return an object (or nothing). This paradigm is very powerful and is even used to get basic control flow without extending the language. Observe this snippet for an example:
(5 < 7) ifTrue:[self doSomething] ifFalse:[self doSomethingElse].
In this example, the object 5 (an instance of the Integer class with value 5) is sent the < message with the argument 7 (another Integer object). The result will be an object of type Boolean (an abstract class - although such things don't exist in Smalltalk, in the loaded sense of the term). In this case, an instance of the Boolean subclass True. Boolean objects have the message ifTrue:ifFalse: as well as the conveniences ifTrue: and ifFalse:, alone. These messages take code blocks (a special type of Smalltalk argument which is interpreted by the VM using normal order reduction (lazily)) and the True subclass overrides the message to invoke the argument to the ifTrue: segment while the False invokes the ifFalse:. As a result, control flow occurs without an actual grammar rule for it.
I always thought this was pretty neat and a good example of how a powerful paradigm can scale. Smalltalk is also interesting in that doing so doesn't make the code hard to understand or excessively long. Something I only found out recently, however, is that this is exactly how control flow is done in the lambda calculus (however, it uses applicative order reduction (eager)). Observe this example of the above operation (I will call the method doSomething A and doSomethingElse B):
(LaTeX notation, since that is as good as any)
(\lambda x. \lambda y. x) A B
In this example, I just hard-coded the comparison of (5 < 7) as true (\lambda x. \lambda y. x) since programming in the lambda calculus is ugly as hell and would have required me writing some really complicated predicate.
In both the lambda calculus example and the Smalltalk example, we see that the value of the predicate does the work of selecting whether we execute the true branch or the false branch of the condition. I found it interesting to notice this since I normally wouldn't have expected a very high level object oriented language to mirror a model of computation (a functional model of computation, at that) in such a direct way.
Any other observations?