Using our knowledge of SIMULA so far, we might write the program shown in example 9.1.
Example 9.1: Simple labels program without classes.
begin integer NumLabs,I; text Nam, Street, Town, County, Code; procedure OutLine(T); text T; begin OutText(T); OutImage end*of*OutLine; text procedure InLine; begin InImage; inspect SysIn do InLine:-Copy(Image.Strip) end*of*InLine; OutLine("Name?"); Nam:-InLine; OutLine("Street?"); Street:- InLine; OutLine("Town?"); Town:- InLine; OutLine("County?"); County:- InLine; OutLine("Code?"); Code:- InLine; OutLine("How many copies?"); InImage; NumLabs:=InInt; Eject(1); for I:=1 step 1 until NumLabs do begin OutLine(Nam); OutLine(Street); OutLine(Town); OutLine(County); OutLine(Code) end endThis example may not be the neatest SIMULA writeable with our current knowledge, but it does the job. It also shows that, within the program, a label is a sequence of five text values, which are first read in and then printed out. What we are really doing, in a clumsy way, is using an object which has five text variables as attributes.
SIMULA allows us to use complex objects, made up of attributes which are already defined. These attributes may be of the standard SIMULA types or may reference types defined by the user, i.e. one user defined type may use others as attributes.
The construction in SIMULA which can be used to declare a complex type is the class. We have already seen predefined system classes when we looked at File and its sub-classes. Now let us declare a class Lab for use in our program. Example 9.2 shows 9.1 reworked using such a class.
Example 9.2: Simple labels program with classes.
begin integer NumLabs, I; procedure OutLine(T); text T; begin OutText(T); OutImage end; text procedure InLine; begin InImage; inspect SysIn do InLine:- Copy(Image.Strip) end; class Lab; begin text Nam, Street, Town, County, Code; end--of--class--Lab; ref(Lab) Label1;! Declare a pointer to a Lab object; Label1:- new Lab;! Create a Lab object and point Label1 at it; comment Remote access through dot notation; Label1.Nam:- InLine; Label1.Street:- InLine; Label1.Town:-InLine; Label1.County:- InLine; Label1.Code:- InLine; InImage; NumLabs:= InInt; comment Now connected access through inspect; inspect Label1 do begin for I:=1 step 1 until NumLabs do begin OutLine(Nam); OutLine(Street); OutLine(Town); OutLine(County); OutLine(Code) end end endThis example may seem longer and more complicated than 9.1. It is certainly true that, for very simple purposes, using classes may offer little advantage. For any but the simplest programs, however, classes can make things much simpler. By the end of this chapter, we shall see this with our labels program.
Let us look at the new features used here. First there is the class declaration. This provides a description for a class of objects which all have the same attributes. In this case we define Lab (label is a SIMULA keyword and may not be used as an identifier). In general, a class declaration is very like a procedure declaration, with the keyword class instead of procedure. We shall look at the precise syntax later.
The declaration of Lab specifies the name of the complex type being defined as the identifier following the keyword class. This identifier is followed by a semi-colon. The attributes of the class are defined in a statement, known as the class body, which follows. Thus Lab has five attributes, all of type text.
Having defined the attributes of our new type, we can now create an object, or as many objects as we like, with those attributes. This is done by using an object generator.
An object generator can be used as a statement on its own or as a reference expression, i.e. on the right hand side of a reference assignment or as a reference parameter. Examples of all these are shown in 9.3.
Examples 9.3: Valid occurences of object generators.
Our labels program uses the commonest and most easily grasped of these, the reference assignment. A variable is first declared, whose type is ref(Lab). This means that it identifies a location where a pointer to an object of the type defined by class Lab may be stored. This variable is used first as the left hand side (destination) of a reference assignment statement.
The effect of this statement is that a new object containing the attributes of Lab is created. Since Label1 is assigned a pointer to this object (references it), the object's attributes can be accessed through the variable Label1. As we have seen with objects which were of types InFile and OutFile, there are two ways of doing this. Both are shown in example 9.2.
"Remote accessing" of a class object is done by using the identifier of a reference variable which currently contains a pointer to the object, Label1 in our example. A ref(Lab) procedure could also be used, as we have seen with SysIn and SysOut. This reference is followed by a dot, followed by the name of a visible attribute of the class which defines the type of the object being accessed.
This method of accessing attributes may be used for both text objects and class objects. This distinction is important, since the type "text" is not defined by a class.
The other way of accessing the attributes of an object is by "connecting" it first. To connect an object we must use an inspect statement. The syntax of a simple inspect statement was described in chapter 8. In the statement which follows the keyword do, the use of any identifier which has a declaration in the class defining the type of the connected object is assumed to refer to this attribute. If no matching declaration is found in this class or its prefixes, the identifier is assumed to belong outside the object.
Thus, within the inspect statement in example 9.2, the occurences of Nam, Street, Town, County and Code are taken to refer to attributes of the object Label1, since declarations for them are found in class Lab.
A full description of remote accessing is given in chapter 13.
9.2 A company wishes to computerise its personnel records. Each record contains the following information:
Name Age Date of birth Works number Job Salary Marital statusDevise a program which will:
We also saw, when we considered class File and its sub-classes, that it is not just data attributes that a class object can contain. The power of the class concept as a way of representing objects in our programs is considerably increased by the ability to define procedures as attributes of classes.
Consider our labels program. In example 9.2, we read in each attribute, one at a time, and wrote it out in the same piecemeal way. In the extended version of exercise 9.1, which inserts a new label in the correct place in a file of labels, all with the same structure, this piecemeal reading will have to occur in several places in the program. We have used the action of copying a single line into a text, repeated five times, to read five lines of label data into the five text attributes of a Lab object. This is really one action on an object of type Lab, so far as our object oriented view of labels is concerned, just as addition is an action on two arithmetic objects.
Example 9.4 shows the labels program again, but this time the reading and writing of the contents of a Lab object are made into procedures local to class Lab. The actions allowed on the object are now included in its definition.
Note how indentation and the use of comments after each end makes the structure of the program much easier to follow.
Example 9.4: Labels program using procedures as attributes of a class
begin integer NumLabs, I; procedure OutLine(T); text T; begin OutText(T); OutImage end--of--OutLine; text procedure InLine; begin InImage; inspect SysIn do InLine :- Copy(Image.Strip) end--of--InLine; class Lab; begin text Nam, Street, Town, County, Code; procedure ReadLabel; begin Nam :- InLine; Street :- InLine; Town :- InLine; County :- InLine; Code :- InLine end++of++ReadLabel; procedure WriteLabel; begin OutLine(Nam); OutLine(Street); OutLine(Town); OutLine(County); OutLine(Code) end++of++WriteLabel; end--of--Lab; ref(Lab) Label1; Label1 :- new Lab; Label1.ReadLabel; InImage; NumLabs := InInt; for I := 1 step 1 until NumLabs do Label1.WriteLabel end..of..programOne major advantage of this approach is that, given a sensible choice of names, we will have a much more readable program. Complicated detail is moved from the main part of the program to the procedure attributes of the class and replaced by meaningful procedure names.
By designing the data structure and the operations to be performed on that structure together, as a class declaration, we make the writing of the main program much simpler. We are freed from detail and can think in high level terms. The essence of object oriented programming is to use good design of class declarations to make the rest of our task easier. Once we had defined ReadLabel as an attribute of Lab, for instance, we no longer had to worry how to read in the data each time it was needed. Any program using our Lab class objects can rely on a standard reading procedure call.
Example 9.4 shows a solution to exercise 9.1 using procedures as attributes of Lab. I think it is much clearer than any solution without them, including that given at the back of this book.
You will probably have noticed that in these examples the procedures InLine and OutLine have not been declared inside the class body of Lab, although they are used only there. This is because they do not refer directly to the data structure which Lab represents. They refer to the more general data structure defined by text and so are declared at the most general level, the program block. This leaves them free for use anywhere in the program that they are useful. ReadLabel and WriteLabel are only useful as part of Lab.
Example 9.4 uses File objects to allow label lists to be accessed and created. Note carefully the use of MyInput and MyOutput, which allows input and output to be switched between the default Files, SysIn and SysOut, and the user defined ones, using the same procedures.
Example 9.5: Inserting a numbered label using procedure attributes.
begin comment******************************************* * MyInput and MyOutput replace SysIn and SysOut. * * They can be redefined as necessary. * **************************************************; ref(InFile) MyInput; ref(OutFile) MyOutput; comment*************************** * Variables used by main program * **********************************; text Request, Source, Output; Boolean Unwritten; integer Count; ref(Lab) NewLabel, NextLabel; comment******************************************** * Utility procedures, used throughout the program * ***************************************************; procedure OutLine(T); text T; begin inspect MyOutput do begin OutText(T); OutImage end end--of--OutLine; text procedure InLine; begin text Tem; inspect MyInput do begin InImage; InLine :- Copy(Image.Strip) end end--of--InLine; comment******************************* * Basic label class definition - Lab * **************************************; class Lab; begin comment * Data attributes of Lab * ; text Nam, Street, Town, County, Code; integer Sequence_No; comment * procedures operating on objects of type Lab * ; procedure WriteLabel; begin MyOutput.OutInt(Sequence_No,10); MyOutput.OutImage; OutLine(Nam); OutLine(Street); OutLine(Town); OutLine(County); OutLine(Code) end++of++WriteLabel; Boolean procedure ReadLabel; begin text First; First :- InLine; if First ne ".end" then begin Sequence_No := First.GetInt; Nam :- InLine; Street :- InLine; Town :- InLine; County :- InLine; Code :- InLine; ReadLabel := True; end end++of++ReadLabel; end--of--Lab; comment********************* * Main program starts here * ****************************; MyInput :- SysIn; MyOutput :- SysOut; OutLine("Please type name of file holding labels"); Source :- InLine; ! Read old label file from SysIn; Output :- Blanks(Source.Length+1); Output := Source; Output.PutInt(Count); ! New list in file Output; OutLine("Do you wish to add another label? Please type Yes or No"); Request :- InLine; while Request="Yes" do begin UnWritten := True; NewLabel :- new Lab; OutLine("Type the new label, using a new line for each item"); if not NewLabel.ReadLabel then OutLine("No new label?"); MyInput :- new InFile(Source); ! Read old list from Source; MyOutput :- new OutFile(Output); ! Write new list to Output; MyInput.Open(Blanks(80)); MyOutput.Open(Blanks(80)); NextLabel :- new Lab; while NextLabel.ReadLabel do begin comment Copy old to new, checking sequence nos.; if NextLabel.Sequence_No>NewLabel.Sequence_No then begin if Unwritten then begin NewLabel.WriteLabel; Unwritten := False; ! Prevent further copies; end end; NextLabel.WriteLabel end*of*copying*file*to*file; OutLine(".end"); MyInput.Close; MyOutput.Close; Count := Count + 1; Source :- Copy(Output); ! Use Output as input for next addition; Output.SetPos(Output.Length-1); Output.PutInt(Count); ! Name of next Output file; MyInput :- SysIn; MyOutput :- SysOut; OutLine("Do you wish to add another label? Type Yes or No."); Request :- InLine end*of*while*"Yes"; MyOutput.OutText("New label list written in file "); OutLine(Source); ! Name of last Output file used; end*of*program
Often the first actions performed on a new object of a particular class follow the same pattern each time one is created. Typically they involve setting the initial values of the data attributes of the object. In class Lab we made this much easier by writing ReadLabel in the definition of the class. This meant that creating and initialising the data in a Lab object required only two statements. By using a simple extension of the class declaration of Lab, we can do it in one.
Consider example 9.6. Here we have a sequence of statements at the end of the class body of Lab. These read in the values of its various attributes. Such a sequence will be executed whenever a new object of this class is generated by new.
Another novel feature is the use of a parameter in the class declaration. Here it is a Boolean, used to indicate whether the new object should prompt for input or merely read without prompting. This can allow interactive input to be treated differently from input from a file. The value of the parameter must be supplied in the object generator.
For the moment we shall treat parameters to classes rather informally, but the following points are important:
Example 9.6: Parameters and initialisation Code in classes.
begin procedure OutLine(T); text T; begin OutText(T); OutImage end--of--OutLine; text procedure InLine; begin InImage; inspect SysIn do InLine :- Copy(Image.Strip); end--of--InLine; class Lab(Prompt); Boolean Prompt; begin integer Sequence_No; text Nam, Street, Town, County, Code; procedure WriteLabel; begin OutInt(Sequence_No,10); OutImage; OutLine(Nam); OutLine(Street); OutLine(Town); OutLine(County); OutLine(Code) end++of++WriteLabel; procedure ReadLabel; begin Sequence_No := InInt; Nam :- InLine; Street :- InLine; Town :- InLine; County :- InLine; Code :- InLine end++of++ReadLabel; comment These actions are performed each time a Lab object is generated; if Prompt then begin OutLine("Type, on separate lines, sequence number, Name, " "Street, Town, County and Code.") end**of**prompting**if**requested; ReadLabel end--of--Lab; ref(Lab) Label1; Label1 :- new Lab(True); ! Use prompting; Label1.WriteLabel end..of..program
We have seen that procedures may also be attributes of classes.
The means of creating an object of a type defined by a class using the object generator new has been explained.
The two methods of remote accessing of attributes of a class object, dot notation and connection by inspect, have been revised.
The concepts of object oriented programming have been explained and we have seen some of the benefits of this approach. We have noted particularly how the use of procedure attributes to manipulate data attributes can simplify the rest of a program.
The inclusion of actions in the definition of classes has been described. Their use in setting initial values for the data attributes has been shown.
Lastly we have seen the use of parameters to classes. The types and modes allowed have been listed and the need to specify them in the object generator has been explained.
What problems would occur if the letter had to be able to contain a large and unspecified number of lines?
9.4 Rewrite your answers to 9.1 and 9.2 using the new features introduced since then. What are the problems when adding several new records, which cannot be assumed to be in order themselves, to an ordered set like those in our labels file? Think especially of a system where the amount of storage space on the computer is limited. What extra features in SIMULA can you think of to help?
Mode | |||
---|---|---|---|
Type | Value | Reference | Name |
Simple type | Default | Illegal | Illegal |
text | Illegal | Default | Illegal |
Object reference | Illegal | Default | Illegal |
Simple type array | Illegal | Default | Illegal |
Reference type array | Illegal | Default | Illegal |
procedure | Illegal | Illegal | Illegal |
type procedure | Illegal | Illegal | Illegal |
label | Illegal | Illegal | Illegal |
switch | Illegal | Illegal | Illegal |