There are many objects in the Smalltalk Environment. Objects that respond to the same messages in the same way are grouped together. When they are grouped together, their private memory is represented in the same way and their methods refer to their data with the same set of names. A group of objects related in this way is called a class. Objects in a group are called instances of the class. Programming in the Smalltalk Environment consist of creating new classes, creating instances of classes, and specifying a sequence of message exchange among all of these objects.
Methods and variables for class behavior are called class methods and class variables, respectively. Class variables have the same naming conventions as instance variables except that the first letter of a class variable must be a capital letter. Class methods on the other hand have the same naming conventions as instance methods.In Chapter 6 "Inheritance", the class variables are shared by multiple classes. For this reason, the class variable name must start with a capital letter.
Instance methods and class methods can refer to class variables, but only instance methods can refer to instance variables. The following diagram will display this example:
The class is a receiver of a class message. For example, this statement sends the class message new to the class Customer:
Example 1: Customer new
Everything in Smalltalk is an object including
the class definition, which happens to be an instance of a class called
Metaclass. From this, we see that a class message is being sent
to an object, which in this case it happens to be an instance of the class
Metaclass. It is not important for the beginning programmer to understand
how class definitions are managed. What is important to understand is that
the class definition, and the definition of class methods and variables,
is an object.
Examples of Class Behavior
The new message from example one above is an example of class behavior. It creates a new instance of the class that receives the message.
Here is an example of maintaining a list of all instances of a class. In this example NCSU Registration wants to keep a list of all of its students. There are many ways to do this, but one way is to add class behavior to Student that keeps track of all Student instances. With this in place, we will be keeping track of students in a list and returning the contents of that list. The following is how we define the methods that are required:
Method Description addStudent Creates a new student and add it to the list. removeStudent: Removes a customer from the list. listOfStudents Returns the list of students.We will define a class variable called ListOfStudents that point to the list of students. Here is the code for each of these class methods:
addStudent "Create a new instance of myself and add it to the list of students." | aStudent | aStudent := self new. self listOfStudents add: aStudent. ^aStudent
removeStudent: aStudent "Remove a student object from the list." ^self listOfStudents remove: aStudent
^self listOfStudents remove: aStudent ifAbsent: [ ].
listOfStudents "Return the list of Students." ListOfStudents isNil ifTrue: [ListOfStudents := OrderedCollection new]. ^ListOfStudentsThe following diagram illustrates the class definition for Customer:.
Here is an example of class methods maintaining common information which is needed by all instances of the class. For example, the class Float has a class method that returns the value of pi. The value of pi is needed by many instance methods for Float. This information doesn't change from instance to instance so it belongs as a class responsibility and not as an instance responsibility.
Any method can get the value of pi by sending the pi message to the class Float. It is shown as follows:
Float pi
1. Select the class that is to be the parent of the new class. 2. Ask that a subclass be added. 3. When prompted for the name, enter one; don't forget that the first character must be upper-case. 4. When prompted for the type of subclass, select subclass.When you are finished, the browser window will hold an expression in the text area. This expression was used to create the class. It can now be modified to change and extend the class. Let's say, for example, that the expression for a new class is TrainSet. What will it look like in the browser? It will look like the following:
Object subclass: #TrainSet instanceVariableNames: ' ' classVariableNames: ' ' poolDictionaries: ' 'The instance variables are added by adding names to the quoted string following instanceVariableNames:. It will look like this in the browser:
Object subclass: #TrainSet instanceVariableNames: 'engine cars caboose track crossings ' classVariableNames: ' ' poolDictionaries: ' 'If the new class TrainSet has a pool dictionary or a class variable, they are added in the same way as above. With the changes, the browser will look like this:
Object subclass: #TrainSet instanceVariableNames: 'engine cars caboose track crossings ' classVariableNames: ' TrackLayout ' poolDictionaries: ' Trains '
Using SalariedEmployee as an example, the following looks like this in external format:
"A subclass of Employee that adds protocol needed for employees with salaries" Employee subclass: #SalariedEmployee instanceVariableNames: 'position salary' classVariableNames: ' ' poolDictionaries: ' ' ! ! SalariedEmployee publicMethods ! position: aString position := aString ! position ^position ! salary: n salary := n ! salary ^salary ! !Here is an explanation for the previous code. The expression starting with Employee subclass: defines the class Employee. This is the same expression that is found in the class or application browsers in the development environment.
The next two lines define a new class, SalariedEmployee, as a subclass of Employee, and has defined two instance variables. The next two lines define any class variable or pool dictionaries. The explanation point, often refer to as a bang, ends the definition.
The next line starts and ends with a bang. It specifies the class and the type, either public or private, of methods that follow. Finally, comes the methods, each ending with a bang. After the last method, another bang is use to indicate the end. With this format, no one ever has to write code. It is the export/import format which is used by IBM Smalltalk.
Examples of Initializing Instances
In the these examples, we will look at the these class methods; key: for the Association class and sortBlock: for the SortedCollection class. In both of these examples, the instances are created and data is set in each instance:
key: newKey "Answer a new Association with an Object, with newKey as the association key." ^self new key: newKey
sortBlock: aBlock "Answer aSortedCollection such that its elements will be sorted according to the criterion specified by the two-argument block aBlock. aBlock must also return a boolean." ^self new sortBlock: aBlock
Examples of Initializing of Class Variables
listOfCustomers "Return the list of customers." ListOfCustomers isNil ifTrue: [ListOfCustomers := OrderedCollection new]. ^ListOfCustomersThe method ensures that the value of the ListOfCustomers instance variable is always valid. In other words not nil. This scheme works as long as no other method has a direct reference to the variable.
Another way to initialize a class variable is to add a new class method that initializes all class variables. This class method would need to have been run once before sending any other class messages to this particular class. The best way to call this class method is to run code from a Workspace that sends this message to this class.
In this example, let's use again the following method for Customer:
initialize "Initialize all class variables." ListOfCustomers := OrderedCollection newThe Customer class needs to receive an initialize message before it can receive any other class messages that depend on the setting of this class variable. The programmer or developer can run the following statement in a Workspace.
Customer initialize.
Class instance variables are like class variables except that each subclass has its own copy. Since it is a private variable, the class instance variable must start with a lowercase letter. Class instance variables support inherited class behavior, with each class having its own state.
Class instance variables are instance variables
that define the state of the class rather than the state of an instance
of a class.
Example of Class Instance Variables
Lets change the variable Persons from a class variable to a class instance variable. It now has a name of persons. To access the data in persons from instance methods, we must send a message to the class.
persons "Return the contents of persons and make sure that the variable is initialized." Persons isNil ifTrue: [Persons := Set new]. ^PersonsThis design now supports three separate lists with only one set of class methods. All three classe,Customer,Vendor, and Person, receive their own copy of this class instance variable, which makes it unique for all of them. There needs to be only one set of class methods which is defined in Person. The following diagram illustrates this example:
Both class variables and class instance variables are important in developing complex Smalltalk applications. Class variables allow common sharing of information across a range of subclasses. Class instance variables allow inheritance of class behavior across the range of subclasses, while allowing each subclass to manage its own class state.