Note: in some versions of Poplog it will not be possible to compile Objectclass directly, with the "lib" or "uses" command. In that case try
compile(`$usepop/pop/lib/proto/objectclass.p');
LIB OBJECTCLASS makes available an object-oriented programming (OOP) extension to Pop-11. This provides a natural extension to the notion of a recordclass with the added features:
o Different classes can share fields, and associated procedures.
o Information can be inherited from one class to other classes (its sub-classes). In Objectclass "multiple inheritance" is supported, so that classes can inherit from more than one superclass.
o Procedures (known as methods) can be defined which behave differently depending on the classes of their arguments. This is already true of some built in procedures: e.g. the arithmetic operators such as + behave differently depending on whether their arguments are integers, bigintegers, decimals, ratios, etc. Because their behaviour depends on the classes (or types) of more than one argument they are sometimes known as "multi-methods". Objectclass includes multi-methods.
o Object Oriented programming also adds an element of "data encapsulation" or "data hiding" in that details of an implementation of a particular type may be hidden from the users of that type. (This is not unique to OOP: it is an aspect of all good programming, and was already an aspect of vectors and records in Pop-11.)
Some OOP systems, e.g. Smalltalk, are based on the notion of "message passing". This is not used by Objectclass: it follows the Common Lisp Object System (CLOS) in using multi-methods instead. All the behaviour of a message passing system can be obtained as a special case.
The Objectclass library is remarkable in the way that it neatly maps OOP ideas onto existing Pop-11 ideas. The correspondence of ideas is as follows :-
methods: procedures, which act according to the type of their arguments. instances: records, the instance variables of which are simply the fields of the record and are accessed by appropriate methods. classes: keys, although the keys that play the role of classes are given some extra fields (via hidden properties) so that they can provide inheritance of behaviour.Because this is a natural mapping, the overhead of a method call is relatively low. This means that the objectclass package provides an efficient means of doing object-oriented programming.
If your Poplog system includes Objectclass, you can get an introduction by looking at TEACH OBJECTCLASS_EXAMPLE. More detailed technical information is provided in REF OBJECTCLASS.
Here is a simple definition for an objectclass to represent people. We assume each person has a name, an age and a sex. The class definition has "slots" for each of these. We can specify default values for some of these attributes, as in the following example:
define :class person; slot person_name = "no_name"; slot person_age = 0; slot person_sex; enddefine;Slots for which no default value is provided will have the word "undef" as value.
You can then use this to create an instance of the class. Various syntactic forms are available for this. Here is one of them, to create an instance of class person, where the variable xxx will have the new instance as its value:
define :instance xxx:person; person_age = 27; person_sex = "female" enddefine; ;;; look at the value of xxx xxx => ** <person person_name:no_name person_age:27 person_sex:female> ;;; xxx can be given a name, as if it were a record with a field ;;; accessor/updater person_name "mary" -> person_name(xxx); xxx => ** <person person_name:mary person_age:27 person_sex:female>
Objectclass methods are procedures that act differently depending on the types (keys) of their arguments. Compare the way the Pop-11 operator "<>" can be applied to words, lists, strings, procedures, etc.
Different definitions of a method are needed for each combination of objectclasses. For example, you could write a method for giving a person a birthday.
define :method birthday( p:person ); lvars age; person_age(p) + 1 -> age; age -> person_age(p); [Happy birthday ^(person_name(p)) - now aged ^age] => enddefine;This method can be applied to xxx
person_age(xxx) => ** 27 birthday(xxx); ** [Happy birthday mary - now aged 28] person_age(xxx) => ** 28It would be possible to define a different version of the "birthday" method for cars. For example, the car version might print out a reminder to get the the car's licence renewed and its insurance revalued. Similarly if "child" were a subclass of "person" then a special birthday method could be defined for instances of child and it would take precedence over the default method for person. E.g. it might light some candles and sing a song.
We can define a new subclass of persons, called adults, with default age 18, who are able to have a spouse, as in the next example. The spouse may be nonexistent, which we'll make the default, represented by the boolean false. Note that the second line of this definition specifies that the adult class is a subclass of class "person". That means that all the slots and methods previously defined for persons will automatically be applicable to adults.
define :class adult; is person; ;;; specify superclass slot person_spouse = false; ;;; and additional slot slot person_age = 18; ;;; A new default age enddefine; define :instance yyy:adult; person_sex = "male"; enddefine;Let's give yyy the name "fred".
"fred" -> person_name(yyy); yyy => ** <adult person_name:fred person_age:18 person_sex:male person_spouse:<false>>The TEACH files referred to give more information including how to define a method called marry, that is applicable to two adults and makes each of them the spouse of the other.
The Graphical Object library gives many more examples, used for defining objects that can be useful components of graphical interfaces, some of whose methods are invoked by actions performed by the user with a mouse.
[To be continued]