All objects in Smalltalk are instances of some class. For example, we
might have an instance p
of the class Point
. Or
3.14 is an instance of the class Float
.
Classes in Smalltalk are objects themselves, and understand certain
messages, just like any other object. One often-used message is
new
, to make a new instance. A variant is
new:
(used for e.g. the class Array). Another common kind of
message is one that gets a constant, for example ColorValue
blue
or Float pi
.
In the Smalltalk browser we can see methods that define class messages by clicking the "class" button instead of the "instance" button. Often built-in classes contain a category "examples" under the "class" messages.
Suppose we want to redefine the new
message to Stacks so that
it automatically initializes the stack. We can do this as follows:
In Smalltalk-72, classes were runtime objects, but they were rather special. They weren't instances of some class themselves. Also if you just mentioned the name, it would create an instance:
In Smalltalk-76, classes are again runtime objects, but they are made part of the normal class-instance scheme. To make an uninitialized instance of the class Point:
Rule: to look up a message name, look in your class. If it's there, use it; otherwise search up the superclass chain. In other words, go up exactly one instance link, and then up 0 or more superclass links.
What is the class Point? In Smalltalk-76 it is an instance of the class Class. Class is a subclass of Object, and an instance of itself. Class understands messages like "new", "instvars", and "compile:" Consequence: all classes understand the same messages!
Thus in Smalltalk-76 initialization must be done like this:
In Smalltalk-80, the designers wanted to allow class-specific initialization messages, e.g.
x:y:
.
Another benefit of this is that it gives the programmer a place to hang
constants and such, e.g. Float pi
In the Smalltalk environment, the class/instance switch in the browser lets one switch between methods the instances understand and methods the class understand (i.e. methods defined in the class and methods defined in the metaclass).
The cost in confusion is huge, though. A particular problem is that new programmers are hit over the head with this right away (unless the teacher glosses over it, which is the usual response).
Alternative 1: back to Smalltalk-76 (c.f. DeltaTalk)
Alternative 2: CLOS style instance creation:
make-instance
creates the new instance, it calls the
function initialize-instance
with the new instance and the
keyword-argument pairs. For example, after make-instance creates
a new point (say p), it evalutes
For example, here is a hypothetical variant of Smalltalk syntax to support this. We would have a class Class, which is an instance of itself.
Point new(x: 5 y: 10)
, the
new
would just gather the parameters and pass them to the
initialize
message to the new instance.
Alternative 3: prototype-based system (see Lecture notes on prototypes)
another use of metaclasses: reflective programming see e.g. "The Art of the Metaobject Protocol"
metaobject protocol in CLOS: "an interface to the language that gives users the ability to incrementally modify the language's behavior and implementation, as well as the ability to write programs within the language"
example of use in CLOS: overriding the way instances are stored -- for example, record-like structure vs. dictionary.