Chapter 2
Thesis
Objects Are Independent Programs
The thread running through a lot of different presentations is that objects are isolated computer programs that communicate by sending and receiving messages. Often, there is an and, but the second clause differs greatly. Let’s ignore it and focus on that first clause.
For example, in Smalltalk-80 and (most of) its descendants, objects could be described as isolated computer programs that communicate by sending and receiving messages and are instances of classes that are organized in a tree structure. The second part here, the part about classes, weakens the first part by reducing the scope of isolation. Why is it required that both the sender and recipient of a message are instances of a class, and that both classes are members of the same tree structure? It is not, so let’s strengthen the idea of isolated programs by removing the constraint on inheritance.
An existing example of an OOP environment with this form of isolation is COM (yes, the Microsoft Component Object Model, that COM). When you receive an object, you know nothing about it but that it responds to the messages defined in the IUnknown—https://docs.microsoft.com/en-us/windows/desktop/api/unknwn/nn-unknwn-iunknown interface, which let you keep a reference to the object, relinquish that reference, or find out what other interfaces it supports. It tells you nothing about where that object came from, whether it inherited from another object, or whether it has fresh, hand-crafted, artisanal implementations of each of its methods.
An inference you can make about both COM objects and Smalltalk objects is that they exist in the same process, that is, the same blob of memory and execution context, as the thing sending them the message. Maybe they internally forward their messages over some IPC (inter-process communication) or RPC (remote procedure call) mechanism, but there is at least part of the object that needs to be in your part of the computer. If it crashes that process, or accesses memory beyond its own instance variables, that impacts the other objects around it. If a Smalltalk object hogs the CPU, other objects do not get to run.
So, while Smalltalk objects approximate the isolated computer programs concept, the approximation is inexact. Meanwhile, on Mach, the only thing a sender knows about an object is a “port,” a number that the kernel can use to work out what object is being messaged. An object could be on a different thread, on the same thread, in a different process, or (at least in theory) on a different computer, and sending it a message works in the same way. The receiver and the sender could share all of their code, inherit from a common ancestor, or be written in different programming languages and running on CPUs that store numbers in a different way, but they can still send each other a message.
Between the extreme of Smalltalk (all objects are the same sort of objects and are related to each other) and Mach there is the concept of the MetaObject—http://wiki.c2.com/?MetaObjectProtocol. As the objects in a software system define how the system models some problem, the metaobjects define how the software system expresses the behavior of its objects. The MetaObject protocol exposes messages that change the meaning of the object model inside the system.
A MetaObject protocol, in other words, lets a programmer choose different rules for their programming environment for different sections of their program. Consider method lookup, for example: in Part One, we saw how any of prototypical inheritance, single inheritance and multiple inheritance, have benefits and drawbacks, and each impose different constraints on the design of an object system. Why not have all of these inheritance tools – and indeed any others, and other forms of delegation – to hand at the same time? With a MetaObject protocol, that’s possible.