(* oops-0 *) (* A first attempt at producing an object oriented environment. *) datatype ('a,'b) method = Method of (string * (('a * 'b) -> 'a)); (* Name of method, function. A method may be applied to an object. A method is a pair ("name",f) where f is a function that takes as arguments a pair of the form ('a,'b) and delivers an 'a. *) datatype ('a,'b) flavor = Flavor of ('a * (('a,'b) method)list); (* Instance variables, list of methods. A flavor can be considered as a prototypical object. It contains the initial value of the instance variables and a list of methods that may be applied to objects of this flavor *) datatype ('a,'b) instance = Instance of (('a,'b) flavor * 'a ref); (* Instance flavor, instance variables. An instance is an object of a given flavor, with its own instance variables *) fun defflavor instance_vars = Flavor(instance_vars,[]); (* Create a new flavor, giving the default instance variables *) fun defmethod name flavour f = let val m = Method(name,f) val (Flavor(ivars,methods)) = flavour in Flavor(ivars,m::methods) end; (* Create a new method for a given flavor. The method has a name (as a string, for example "move") and a function ('a,'b) - > 'a. An example follows: a flavor f1 is a pair, considered as representing a point in 2-D space. Methods are created to move to a new absolute location (move) or move relative (add) *) val f1 = defflavor (0,0); fun move (pos1,pos2) = pos2; val f1 = defmethod "move" f1 move; fun add ((x:int,y:int),(i:int,j:int)) = (x+i,y+j); val f1 = defmethod "add" f1 add; (* Note that when a method is added to the flavor, a new flavor is created. It might be better to have the list of methods as being a reference to a list of methods. But there is a problem in that this cannot be initialised. That is you cannot do the following: "val x = ref []". Do you know why? *) fun make_instance flavour = let val Flavor(ivars,_) = flavour in Instance(flavour,ref ivars) end; (* Create an instance of a flavor. Note that the instance has instance variables that are "references" and can thus be modified rather than re-created (that is a modification is genuine, it is not psuedo-modification by recreation *) exception not_found; fun find_method msg [] = raise not_found |find_method msg ((Method(name,f))::x) = if msg=name then f else find_method msg x; (* Given a message (msg is a string) and a list of methods (pairs of (name,f)) find the appropriate function f. *) fun send message object args = let val Instance(flavour,ivars) = object val Flavor(_,methods) = flavour val f = find_method message methods in ivars := f ((!ivars),args); object end; (* Send a message to an object, along with a set of arguments. The flavor of the object is found, from this can be found the list of methods of that flavor. The appropriate function is found from the method list. The function is then applied to the pair (a,b) where a is a derefrencing of the instance variables of the object, and b is the arguments passed along with the message. The method delivers a new "a" that is assigned to the instance variables of the object *) fun describe object = let val Instance(flavour,ivars) = object val Flavor(_,methods) = flavour in (!ivars,map (fn a => let val Method(n,_) = a in n end) methods) end; (* Describe an object (aka instance). Deliver a pair (a,b), where a is the instance variables of the object and b is a list of method names attached to the flavor of the object. Note that ivars, the instance variables, are dereferenced. *) fun inst_vars (Instance(_,ivars)) = !ivars; (* Given an object, deliver its instance variables. Again note dereferencing of ivars. *) val p1 = make_instance f1; (* Create an instance, p1 *) describe p1; inst_vars p1; send "move" p1 (3,2); (* Move p1 to location (3,2) *) inst_vars p1; send "add" p1 (1,2); (* Move p1 relative (1,2) *) inst_vars p1; (* Okay .... What's the problem here? (1) Attempt to create a new method that alters only the y co-ordinate of an instance of f1. That is create a function inc_y((x:int,y:int),j:int) = (x,y+j) and make it a method of f1, using defmethod. What's the problem? (2) Attempt to produce a flavor that is a "mix" of other flavors. Can you see a way to implement inheritence? (Let me know!). *)