Contents
Next

Classes


A class describes a data structure in terms of its variables and its algorithms. This section shows how a very simple data structure is implemented as a class and it shows how this data structure can be extended by a subclass.

First we discuss the data-type like aspects of classes.

Object subclass: #Person
    instanceVariableNames: 'name givenName dateOfBirth'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Tutorial'

This data type has three fields - instance variables - to store a persons name, given name and date of birth. The instance variables name and givenName shall take string values, the value of instance variable dateOfBirth is assumed to be a Date. These details are not declared and cannot be checked by the Smalltalk compiler.

The structure of the class is depicted by this diagram:

Diagram showing the elements of 'Person'

The title gives the name of the class, the part below the title contains the data fields - the variables - of the class.

A variable of type Person is created with:

  | instanceOfPerson |
instanceOfPerson := Person new.
instanceOfPerson

To examine the object that you create with this piece of code, you should evaluate it with 'inspect it'. You will get an inspector view that you can use to read (and to modify) the values of the instance variables of the object.

new is a message to a class that creates a new instance of the class. When sent to class Person, this message allocates memory for a new Person and answers this new person. In some programming languages, new is called a constructor, in others, it is called a memory allocation operator.

The class method new initializes all instance variables of a new instance with the value nil.

To access the fields of the data structure, we need access functions.

setName: aString
  name := aString.
getName
  ^name.
setGivenName: aString
  givenName := aString.
getGivenName
  ^givenName.
setDateOfBirth: aDate
  dateOfBirth := aDate.
getDateOfBirth
  ^dateOfBirth.

With these access methods, we can now create a record that describes a person:

  | instanceOfPerson |
instanceOfPerson := Person new.
instanceOfPerson
     setName: 'Churchill';
     setGivenName: 'Winston';
     setDateOfBirth: (Date newDay: 30 month: 11 year: 1874).
instanceOfPerson

When you evaluate this with 'inspect it', you can see that all instance variables have now values. Select the instance variable dateOfBirth and inspect it: You see that a date is in turn an object with instance variables.

To create a record of type 'Person' - an instance of class 'Person', as we prefer to say it in the terminology of Smalltalk, we can define an instance creation method:

name: familyName givenName: givenName dateOfBirth: aDate
 ^self new
    setName: familyName;
    setGivenName: givenName;
    setDateOfBirth: aDate.

This method is defined on the class side of the protocol. With this class method, we can create an initialized instance with one single statement:

  | instanceOfPerson |
instanceOfPerson :=
   Person name: 'Churchill';
          givenName: 'Winston';
          dateOfBirth: (Date newDay: 30 month: 11 year: 1874).
instanceOfPerson

One may think that a class method is essentially a convenient shorthand notation for instance creation. But in fact it is more than that: A class method creates and initializes an instance.

The use of individually defined instance creation methods facilitates the creation of fully initialized instances. The creation of incompletely initialized instances is thus easily avoidable. The definition and use of individually crafted instance creation methods is therefore highly recommended. Interesting examples of individually defined instance creation methods can be found in the class protocol of some view classes. The interested reader should look at:


Subclasses

Often, we have to keep additional data for certain kinds of persons. For an employee, we want additionally to know the kind of work he does, his salary and the department where he passes the working days.

An employee is of course a person, but one in a specific role for which additional information is available. To store that additional information, it is desirable to extend the definition of class Person. This is possible, it is even easy: We define a subclass, that adds additional instance variables and additional methods to its superclass:

Person subclass: #Employee
    instanceVariableNames: 'kindOfWork salary department dateOfHirement'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Tutorial'

The diagram of the class shows that the instance variables of the superclass are inherited:

Diagram showing the elements of 'Employee'

The class Employee inherits also all instance methods and all class methods from its superclass.

To complete the definition of class Employee, we have to add some instance methods:

kindOfWork: aString
  kindOfWork := aString.
kindOfWork
  ^kindOfWork.
salary: anAmount
  salary := anAmount.
salary
  ^salary.
department: aString
  department := aString.
departement
  ^department.
dateOfHirement: aDate
  dateOfHirement := aDate.
dateOfHirement
  ^dateOfHirement.

What we have learned:


Contents
Next