| |
 |
|
This program defines a linked list record type, List
(along with a pointer type PList) that stores values of
type PDisplayable. The PDisplayable type can be
thought of as an 'abstract class' that defines a Display
method, even though IMCP does not support abstract classes
directly. The Integer type is a 'wrapper class' for
INTEGER primitives, and extends the Displayable type. For
the purposes of convenience, we define a Helper type that
is used to store a simple 'constructor' method,
NewPInteger. (The typical convention in Component Pascal is to
write a 'constructor' procedure for each record type, but as IMCP
does not support non-method procedures we must define the
constructor for a record type).
The main body of the program constructs a new list, insert
elements into that list, and then extracts the first and last
elements of the list. Notice that we downcast the list elements to
their dynamic type, PInteger, in order to get at the
val field. This is an example, admittedly somewhat contrived,
of a typical object-oriented programming paradigm for collections
classes in which the stored elements need to be downcast when
extracted from the collection. This weakness in the type system is
rectified with the introduction of generics in IMCPG.
The other example of a slightly restrictive style in this program
is the use of PDisplayable as the element type in the
list; the introduction of interfaces in IMCPI makes the
program a little more natural.
MODULE ListMod; (* Example program for Imperative MCP *)
TYPE
(* An 'abstract' supertype for 'displayable' records *)
Displayable = EXTENSIBLE RECORD (ANYREC) END;
PDisplayable = POINTER TO Displayable;
(* A simple wrapper record to use in our linked list *)
Integer = EXTENSIBLE RECORD (Displayable)
val: INTEGER;
END;
PInteger = POINTER TO Integer;
(* A linked list of PDisplayable elements *)
List = EXTENSIBLE RECORD (Displayable)
head: PDisplayable;
tail: PList;
END;
PList = POINTER TO List;
(* A helper class containing useful constructors *)
Helper = RECORD (ANYREC) END;
PHelper = POINTER TO Helper;
VAR
list: PList; (* the root node of our linked list *)
helper: PHelper; (* our helper object *)
head: PDisplayable; (* we will store the head of the list here *)
PROCEDURE (this: PDisplayable) Display (), NEW, EXTENSIBLE;
BEGIN
util.WriteString("PDisplayable.Display()\n");
END Display;
PROCEDURE (this: PInteger) Display ();
BEGIN
util.WriteInt(this.val);
END Display;
PROCEDURE (this: PList) Display ();
BEGIN
IF util.Not(util.PEquals(this.head, NIL)) THEN
this.head.Display();
END;
util.WriteString("\n");
IF util.Not(util.PEquals(this.tail, NIL)) THEN
this.tail.Display();
END;
END Display;
PROCEDURE (this: PList) Insert (elem: PDisplayable), NEW, EXTENSIBLE;
VAR
newList: PList;
BEGIN
IF util.Not(util.PEquals(this.tail, NIL)) THEN
this.tail.Insert(elem);
ELSE
NEW(newList);
newList.head := elem;
this.tail := newList;
END;
END Insert;
PROCEDURE (this: PList) Head (): PDisplayable, NEW, EXTENSIBLE;
BEGIN
RETURN this.head;
END Head;
PROCEDURE (this: PList) Last (): PDisplayable, NEW, EXTENSIBLE;
VAR
retVal: PDisplayable;
BEGIN
IF util.Not(util.PEquals(this.tail, NIL)) THEN
retVal := this.tail.Last();
ELSE
retVal := this.head;
END;
RETURN retVal;
END Last;
PROCEDURE (this: PHelper) NewPInteger (val: INTEGER): PInteger, NEW;
VAR
p: PInteger;
BEGIN
NEW(p);
p.val := val;
RETURN p;
END NewPInteger;
BEGIN
util.WriteString("ListMod test program\n");
NEW(list);
NEW(helper);
list.head := helper.NewPInteger(5);
list.Insert(helper.NewPInteger(10));
list.Insert(helper.NewPInteger(12));
list.Display();
head := list.Head();
WITH head: PInteger DO
util.WriteInt(head.val);
util.WriteString("\n");
END;
head := list.Last();
WITH head: PInteger DO
util.WriteInt(head.val);
util.WriteString("\n");
END;
END ListMod.
|