We have left out inessential portions of the code the program in order to conserve space. The keyword include used in the definition of simply indicates that all methods declared in are also included in .
program heterogeneous_linked_lists; -- Program developing heterogeneous singly- and doubly-linked lists. -- Elements of the linked list must be of type which matches rect_type. type rect_type = ObjectType gt: func(#rect_type):bool; eq: func(#rect_type):bool; get_height: func():integer; draw: proc(); end ObjectType; Node_type = ObjectType get_next: func():mytype; get_val: func():#rect_type; set_next: proc(mytype); set_val: proc(#rect_type); attach_right: proc(mytype) end ObjectType; DbleNode_type = ObjectType include Node_type get_prev:func():mytype; set_prev:proc(mytype); end ObjectType; TypeFunction OrdList_type(U <# Node_type) = ObjectType find: func(#rect_type):bool; add: proc(U); drawall: proc(); end ObjectType; classes class gen_rect_class(tp,lft,bot,rght,newz: integer) var top = tp: integer; left = lft: integer; bottom = bot: integer; right = rght: integer; z = newz: integer; methods function gt(other: #rect_type): bool begin return (z > other.get_height()) end; function eq(other: #rect_type): bool ... function get_height(): integer ... procedure draw ... end class; class Node_class(v: #rect_type) var val = v: #rect_type; next = nil: mytype; methods function get_next(): mytype begin return next end; function get_val(): #rect_type begin return val end; procedure set_next(nxt:mytype) begin next := nxt end; procedure set_val(vl: #rect_type) begin val := vl end; procedure attach_right = procedure(newNext: mytype) begin self.set_next(newNext) end; end class; class DbleNode_class(v: #rect_type) inherits Node_class(v) modifying attach_right var prev = nil: MyType methods function getPrev():MyType ... procedure setPrev(newPrev: MyType) ... procedure attachRight(newNext: MyType) begin self.setNext(newNext); newNext.setPrev(self) end end class; class OrdList_class(U <# Node_type) var head = nil: U; methods function find(match:#rect_type): bool var current: U; begin current := head; while (current != nil) & match.gt(current.get_val()) do current := current.get_next() end; if (current != nil) & (current.get_val()).eq(match)) then return true else return false end; procedure add(new_node:U) var prev: U; current: U; begin if head = nil then head := new_node; new_node.set_next(nil); else if head.get_val().gt(new_node.get_val()) then new_node.attach_right(head); head := new_node; else prev := head; current := head.get_next(); while (current != nil) & current.get_val().gt(new_node.get_val()) do prev := current; current := current.get_next(); end; if current = nil then prev.attach_right(new_node); new_node.set_next(nil); else new_node.attach_right(current); prev.attach_right(new_node); end; end; end; end; drawall = procedure() var current: U; cur_val: #rect_type; begin current := head; while (current != nil) do cur_val := current.get_val(); cur_val.draw(); current := current.get_next(); end; end; end; end class; var temp_rect: rect_type; shape: #rect_type; lnode: Node_type; dnode: DbleNode_type some_node: #Node_type; slist: #OrdList_type[Node_type]; dlist: OrdList_type[DbleNode_type]; begin -- main program temp_rect := new(gen_rect_class(1,1,4,4,5)); lnode := new(Node_class(temp_rect)); slist := new(OrdList_class(Node_type)); dnode := new(DbleNode_class(temp_rect)); dlist := new(OrdList_class(DbleNode_type)); slist.add(lnode.clone()); -- illegal: slist.add(dnode.clone()); -- Can't add a doubly-linked node to a singly-linked list. -- illegal: slist := dlist -- OrdList_type[DbleNode_type] does not match OrdList_type[Node_type]. temp_rect := new(gen_rect_class (2,2,3,3,2)); lnode.set_val(temp_rect); slist.add(lnode); some_node := dnode.get_next(); lnode := lnode.get_next(); shape := lnode.get_val(); -- illegal: temp_rect := lnode.get_val(); -- Result of get_val() has type #rect_type. lnode.setval(shape) PrintNum(shape.get_height()); end.
The two new type-checking rules for #-types introduced in section 11 are necessary to type check this program. The first states that if an expression has type , then also has type #T. The second states that if has type #T and , then also has type #U. The first of these rules allows the assignment to and the use of as a parameter in the message send . Both of these rules are used in type checking the assignment to .
The program is written with a syntax and style similar to that of the language LOOM [BP96]. LOOM differs from the above in a few syntactic details. It also supports the use of classes as first-class values (e.g., classes can be returned as values from functions), provides finer control over the visibility of methods, and includes a module system for programming in the large. A description of the module facilities can be found in [Pet96].