[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.7 OO programming

Smalltalk: an Example OO Language

The following notes introduce OO using the Smalltalk language. After programming in LISP, you may be very happy with Smalltak- often the code has no brackets!

Until 5 years ago, I would have said that Smalltalk is was an historical language (something to be studied by ancient scholars). Now, maybe not (see all the interest in Seaside and GNU Smalltalk).

Anyway, we don’t study it to program in it. Rather, we use it to define an abstract spec of what an OO language should look like. From that, we will then audit GOLD- an OO language written in 100 lines of LISP.

History

Smalltalk was developed at Xerox Parc in the 1970s by a team that included Alan Kay, Dan Ingalls, Adele Goldberg, Ted Kaehler, Scott Wallace, and others. Alan Kay is famous for saying

The best way to predict the future is to invent it.

He wasn’t kidding. Smalltalk is famous for creating the bitmapped multi-windowed mouse-driven environment that inspired Steve Jobs to create the first Macintosh. Up until the iPhone/iPad, the Smalltalk interfaces were the dominant influence on our vision of a computer. Consider the following images from the Sept 1977 Scientific American Article, "Microelectronics and the Personal Computer" pp. 230-244, by Alan Kay. Note the definition of some core ideas:

"Windows," display frames within the larger display screen, enable the user to organize and edit information at several layers of refinement. Once the windows are created they overlap on the screen like sheets of paper. Images with various degrees of symbolic content can be display simultaneously.

alto-4 alto-c

But What are Objects?

Lets take a moment to review the seven main buzzwords of OO:

Classes make instances and, usually, distinction is as follows:

(By the way, here’s something really cool. Everything in Smalltalk is an instance, including classes:

Instances have attributes, operations, identity, and associations.

Instances can use inheritance, classification, encapsulation and polymorpishm:

For Example

For example, you could be modeled as a network of associations between instances of the class "Body", "Arm", and "Leg":

Note classic newbie OO mistake: associations is not inheritance;

So it is not true that "Arm" isa "Body". Rather, "Body" uses "Arm".

For another example, "Fraction" contains two integers: the "Numerator" and the "Denominator". "Fraction" is not a sub-class of "Integer"- but it does use Integers.

Lesson: a working OO system is a conversation between networks of objects.

cars

Talking from Sub to Super

Let’s say that we’ve got an Account class:

Object subclass: #Account
          instanceVariableNames: 'balance'
          classVariableNames: ''
          poolDictionaries: ''
          category: nil !

!Account methods !
spend: amount
     balance := balance - amount
!
deposit: amount
     balance := balance + amount
!
init
      balance := 0
!!

This last init method initializes the hidden variable "balance" (actually called an instance variable ) to zero, which makes sense for an account balances.

We can create the Savings class as a subclass of Account. It holds money, just like an Account, but has an additional property that we will model: it is paid interest based on its balance.

Account subclass: #Savings
   instanceVariableNames: 'interest'
   classVariableNames: ''
   poolDictionaries: ''
   category: nil !

The instance variable "interest" will accumulate interest paid. Thus, in addition to the "spend:" and "deposit:" messages which we inherit from our parent, Account, we will need to define a method to add in interest deposits, and a way to clear the interest variable (which we would do yearly, after we have paid taxes). We need to define a method for allocating a new account - we need to make sure that the interest field starts at 0.

!Savings methods !
init
     interest := 0.
     ^super init
!!

Can you guess what super init does? Its the sub-class method calling the parent. It is like saying "do my own initializations for my own variables (interest) then go away and do whatever you need to do to initialize my inherited properties.

While this is a trivial example, such definitions-via-extension are very useful when dealing with (say) complex interface classes where super-classes have some intricate initialization sequence. Subclasses need not understand that initialization sequence, all they need to do is to call daddy and ask him to run that complex code.

One of our challenges for GOLD is to handle such super-class calls.

Singletons

As an aside (and this is a concept we will return too in later lectures) is that one thing you want to with initialization control is handle singletons; i.e. classes for which there should only be one instance, and provide a global point of access to it.

Why singletons? Well, often, a system only needs to create one instance of a class, and that instance will be accessed throughout the program. Examples would include objects needed for logging, communication, database access, etc. You could pass such an instance from method to method, or assign it to each object in the system. However, this adds a lot of unnecessary complexity.

Singletons are most appropriate for services that do not change their nature based on their invocation context. A singleton can be created at startup based on context or be reset for larger scale state transitions

Simply put: singletons make it easy to compose a program from different components. Singletons do not create unnatural interdependencies made by passing a context object around, where every piece of code will bind to everything in the context object. Singletons stand alone.

Examples:

How to do it in Smalltalk?

Step 1: add a ClassVariable to a class.

Account subclass: #Database
   instanceVariableNames: ''
   classVariableNames: 'CurrentDatabaseConnection'
   poolDictionaries: ''
   category: nil !!

Step 2: change the new method that only returns the same instance, over and over again.

!Database class methods!
new
	CurrentDatabaseConnection isNil ifTrue:[
		CurrentDatabaseConnection := super new].
	^CurrentDatabaseConnection
!!

That’s it! Now, whenever we create a "new" instance of this class, we just use the same one over and over again.

Note that there is a much much much more elegant way to create Singletons (see the uber-elegant way Io does it, on p72-74- which we’ll explore in later lectures).

What Makes OO Exceptional: Distributed Control

In the above example, we could specialize instance creation by writing a new "new" method, that runs just for one exceptional class (DataBase’s singleton method).

That’s OO- everything is exceptional. Polymorphism means that general procedures that can specialized for particular objects without mucking up the centralized controller.

To illustate that point, we take a look at how procedural control can be defined in an OO system.

Blocks

Before doing that, we have to know about "Blocks" which is Smalltalk’s version of lambda bodies.

|x y z|
x := [3 > 7].
y := [:a | a > 7].
z := [:a :b | a > b].

x value.              "Returns true"
y value: 10           "Returns false"
z value: 10 value: 20 "Returns false"

Distributed if-then-else

All control in Smalltalk is based on blocks. The message

3 > 7 ifTrue: [Transcript printOn: 'yes'].

The way this works is that: 3 > 7 evaluates to some subclass of Boolean:

The code for those methods is shown below:

! True methods !
ifTrue: trueBlock
	^trueBlock value "We are true -- evaluate trueBlock"
!!

! False methods !
ifTrue: trueBlock
	^nil "We are false -- do nothing"
!!

Note that this is an example of pure OO: the object-oriented message system is being enlisted to replace procedural if-then-else.

Distributed Enumeration Control

Using Blocks, trick, we can also implement for-loops. Here’s the equivalent of LISP’s dotimes macro:

! Number methods !
to: stop do: aBlock 
        | i |
        i := self.
        [i <= stop] whileTrue: [ "whileTrue is a built-in"
                aBlock value: i.
                i := i + 1
        ]
        ^stop
!!

For example:

1 to: 5 do: [:i|
   Transcript printOn: i]

And here the equivalent of LISP’s dolist macro:

! SequenceableCollection methods !
do: aBlock
    1 to: (self size) do: [:i | 
           aBlock value: (self at: i)]
!!

For example:

'this is a string' do: [:char|
   Transcript printOn: char]

Why Bother?

Now consider the advantages of such distributed control structures:

Which means, extending the language to bury away common processing constructs inside higher-level commands is much easier than in "C".

So there is a whole industry in building domain-specific languages. For example, here’s a state machine language, written in Smalltalk. Each machine contains states (e.g. #start, #run) which are connected by transitions (e.g. if happiness < 2 then go to #run).

! Factory methods !
worksIn: factory
    factory 
       machine: (self new: 'party boy');
       go: #start   to: #run     then:  [The machine talks: 0];
       go: #run     to: #oddHaHa then:  [The machine talks: 1];
       go: #run     to: #even    then:  [The machine talks: 2];
       go: #oddHaHa to: #oddHaHa then:  [The machine 
                                            drinks; 
                                            talks: 3];
       go: #oddHaHa to: #run     if:    [The machine happiness < 2 ] 
                                 then:  [The machine 
                                            talks: 4;
                                            talks: 'Too drunk to stay awake.'];
       go: #even    to: #run;
       go: #run     to: #endF    if:    [App random next > 0.9] 
                                 then:  [The machine 
                                            talks: 5;
                                            talks: 'that is all folks'.
                                         The yourself oo.
                                         The state oo.
                                         The next oo.
                                         The machine oo.
                                         The factory oo].
!! 

For more on this language, see the agent-ready code base.

For more on domain-specific languages see my notes on that topic.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

This document was generated on April 19, 2011 using texi2html 5.0.