Smalltalk


Object-oriented features

Classes and objects, by example

We will see what Smalltalk classes and objects look like by considering how to write a point class:
	class name		Point
	super class		Object
	instance var		x   y
	class var		pi
	class messages and methods

		newX:xvalue Y:yvalue | |
		^ self new x: xvalue
			   y: yvalue		

		newOrigin | |
		^ self new x: 0
			   y: 0

		initialize | |
			pi <- 3.14159

	instance messages and methods
		x: xcoord y: ycoord | |
			x <- xcoord
			y <- ycoord

		moveDx: dx Dy: dy | |
			x <- dx + x
			y <- dy + y

		x | | ^x
	
		y | | ^y

		draw | | << code to draw point >>

Suppose we execute the following code:
	p <- Point newOrigin
	p moveDx: 3 Dy: 4
What would be the values of
	p x		(3)
	p y		(4)
Run-time Structures for points

The (unoptimized) run-time structure for Points looks like:











Insert picture
Note that this picture is schematic; actual implementations might perform various optimizations to improve performance.

Inheritance, by exmple

We will look at inheritance by considering a color point object.

	class name		Colored Point
	super class		Point
	instance var		color
	class message and methods

		newX: xvalue Y:yvalue C:cvalue | |
			^ self new x: xvalue y:yvalue color:cvalue

	instance messages and methods

		draw | | << draw color point >>
	
Suppose we execute the following code:
	cp <- ColoredPoint newX:1 Y:2 C:"red"
	cp moveDx: 3 Dy: 4
What would be the values of
	cp x		(4)
	cp y		(6)
Run-time structure to support inheritance

The (unoptimized) run-time structures for colored points might look like:




insert picture here.
Again, this picture is schematic. An actual compiler would probably perform a number of optimizations to improve performance. One such optimization is to cache recently found methods within a given class.

Dynamic Lookup

Ingalls' made frequent reference to something he called "polymoprhism" in his lecture. He meant that the same message name invokes different code depending on the object that receives the message. Today we would call this ability "dynamic lookup", meaning the code to execute depends on the run-time value of the receiver object. This mechanism is an extremely useful.

Consider for example a list of objects, some of which are points, others of which are colored points. If we wanted to display every point on the list, we could traverse the list, sending each object the draw method. Because of dynamic lookup, the point objects will execute the point draw method and the colored points will execute the colored point draw method. Dynamic lookup supports code re-use, since one routine will display lists of points, lists of colored points, and lists that have both points and colored points.

The run-time structures above support dynamic lookup in two ways.

1. The methods are selected through the receiver object.
2. Method lookup starts with the method dictionary of the class of the receiver, and then proceeds upward. The first method found with the appropriate name is selected.

"Subtyping"

Smalltalk is an untyped language, so to some extent it is meaningless to ask about subtyping in Smalltalk. However, if we recall the definition of a subtype:
	A type B is a subtype of a type C if any context expecting
	an expression of type C may take any expression of type B
	without introducing a type error.
we can see that subtyping is about substitutivity: when may we safely replace one object with another without introducing an error? This notion makes sense for Smalltalk, even in the absence of types. In Smalltalk, we say that one object ob1 conforms to another ob2 if no context expecting ob2 will produce a new error if given ob1 instead.

What must be true about ob1 and ob2 for this relationship to hold between them?

Is there any necessary relationship between the classes that created ob1 and ob2?

Connections between inheritance and subtyping

In Smalltalk, it is often the case that if class C2 inherits from class C1, then the objects instantiated from C2 conform to the ones instantiated from C1.

Why does this make sense in general?

When would this relationship not hold?

Message sending: flexibility vs. efficiency

In C++, we will see that message sending can be optimized so that when we send a message m to an object ob:
	ob <= m
we can determine statically which slot in ob's vtable (method dictionary) the method m lives, so method lookup can be done in constant time in C++.
1. Why is such an optimization not possible in Smalltalk?
2. What does Smalltalk gain for this loss of efficiency?

Pseudo-variables self and super

An object can send messages to itself via the pseudo-variable self. Self is called a pseudo-variable because its value can only be read, not written. Within a given method m, self refers to the host object, ie, the object that the method m lives in.

The pseudo-variable super is similar, except that when a message is sent to super , the search for the appropriate method body starts with the object's parent class, instead of the object's class. This mechanism provides a way of accessing a parent class's version of a method that has been overidden in a subclass class.

Encapsulation

Smalltalk adds encapsulation to Simula. In Smalltalk,
Instance variables are only accessible to the class C in which they are declared and in all classes derived from C. (This level of access corresponds to C++'s protected access level)

Methods are accessible everywhere. (They are public in C++ terminology).

Smalltalk Summary

1. Objects: created via classes. At run-time, store instance variables and a pointer to the instantiating class.

2. Classes: object definitions. At run-time, store pointers to templates, method dictionaries, and parent classes.

3. Inheritance: one class's definition may cite another class C as a superclass, in which case the derived class inherits the instance variables and methods of the class C. Methods that are present in the parent class may be redefined in the derived class.

4. Subtyping: Conformance relation. Depends on messages understood, but not underlying representations or inheritance hierarchy.

5. Encapsulation: protected instance variables public methods.


Kathleen Fisher / kfisher@cs.stanford.edu