This rule captures the essence of programming in Smalltalk.
In procedural programming, the choice of which piece of code to execute when a procedure is called is made by the caller. The caller chooses the procedure or function to execute statically, by name.
In object-oriented programming, we do not “call methods”: we “send messages.” The choice of terminology is significant. Each object has its own responsibilities. We do not tell an object what to do by applying some procedure to it. Instead, we politely ask an object to do something for us by sending it a message. The message is not a piece of code: it is nothing but a name and a list of arguments. The receiver then decides how to respond by selecting its own method for doing what was asked. Since different objects may have different methods for responding to the same message, the method must be chosen dynamically, when the message is received.
3 + 4 → 7 "send message + with argument 4 to integer 3" (1@2) + 4 → 5@6 "send message + with argument 4 to point (1@2)"
As a consequence, we can send the same message to different objects, each of which may have its own method for responding to the message. We do not tell the
SmallInteger 3 or the
Point 1@2 how to respond to the message
+ 4. Each has its own method for +, and responds to
+ 4 accordingly.
One of the consequences of Smalltalk’s model of message sending is that it encourages a style in which objects tend to have very small methods and delegate tasks to other objects, rather than implementing huge, procedural methods that assume too much responsibility. Joseph Pelrine expresses this principle succinctly as follows:
Don’t do anything that you can push off onto someone else.
Many object-oriented languages provide both static and dynamic operations for objects; in Smalltalk there are only dynamic message sends. Instead of providing static class operations, for instance, classes are objects and we simply send messages to classes.
Nearly everything in Smalltalk happens by message sends. At some point action must take place:
- Variable declarations are not message sends. In fact, variable declarations are not even executable. Declaring a variable just causes space to be allocated for an object reference.
- Assignments are not message sends. An assignment to a variable causes that variable name to be freshly bound in the scope of its definition.
- Returns are not message sends. A return simply causes the computed result to be returned to the sender.
- Primitives are not message sends. They are implemented in the virtual machine.
Other than these few exceptions, pretty much everything else does truly happen by sending messages. In particular, since there are no “public fields” in Smalltalk, the only way to update an instance variable of another object is to send it a message asking that it update its own field. Of course, providing setter and getter methods for all the instance variables of an object is not good object-oriented style. Joseph Pelrine also states this very nicely:
Don’t let anyone else play with your data.