MuLE Class Creation/Object Making Lab

The SOOP Interpreter.

 

Assumptions

This lab assumes an understanding of first class functions and objects, the ability to write functions that return functions and familiarity with object oriented programming, especially class and object creation. (Knowledge DrScheme and the MuLE environment is also necessary.)

 

Objective

The goal of this laboratory is to explore objects by implementing them in the SOOP interpreter. A secondary goal is to understand that objects are simply an encapsulation of state and methods to access and manipulate that state and to see that this can be implemented through functions as well as objects.

 

Overview

SOOP is composed of three files, soop.s, soop.win, and soop.obj. The soop.s file contains a simple interpreter for the SOOP environment while the soop.win file contains the special utility code that creates the visual representation of objects. Finally, soop.obj provides the classes that are accessible in the SOOP environment.

The SOOP interpreter is similar but far simpler than the other interpreters in MuLE. It consists of a parse function and an execute function. Besides the normal MuLE commands (ie, list, clear, help), the SOOP parse function recognizes only numbers, symbols, special "make" words and the commands assign and send. The assign command binds objects to variables and the send command sends a message to a variable. The SOOP interpreter itself doesn’t recognize any of the messages that it sends, it only passes the messages on to the named object.

The "make" words create objects. For example, an instance of the variable class (called a "box" in SOOP) is created by calling make-box, an instance of the stack class is created by calling make-stack, etc. Every class must provide a "make" function which must be included in the SOOP variable MAKEWORD. The MAKEWORD variable is simply a list of all the make-functions that are recognized by SOOP. Thus the user of SOOP cannot create a class in the SOOP environment, s/he can only create instances of classes already recognized by SOOP. Only the programmer of the SOOP interpreter can create new classes.

 

The Details: Creating Classes

To create a class, a new function must be written that takes no arguments and returns a function that receives exactly two parameters, an environment and a message (which could be any type including a list of arguments). By convention this function is called make-class where class is the name of the new class to create. In fact, any name can be used for the function. The make-class name must be added to the MAKEWORD list that is defined and used in the soop.s file and the make-class function itself must be added to the soop.obj file.

In the SOOP interpreter implementation, a class is a function that returns a function and an object is an instance of the returned function. For example, to create a box object in SOOP, the syntax in the following statement is used.

(assign x make-box)

The SOOP parser recognizes the assign keyword and creates a parse tree that includes the variant record bind and the variant record make-exp (containing the symbol "make-box"). The execute function evaluates the "make-box" function stored in the make-exp record and binds the resulting function to the symbol x in the environment.

Later, the object (i.e the function) bound to x could be sent a message through the statement:

(send x set-val 10)

In this case the SOOP parser recognizes the send keyword and creates a record containing two fields, one for the message (set-val) and one for all of the arguments (in this case 10). The execute function "sends" the message to the object bound to x, in effect, calling the function bound to x and passing the arguments set-val and 10.

Adding a new class does not involve changing the SOOP interpreter itself, rather a function make-class must to be added to the MAKEWORD list and the make-class function itself to the soop.obj file. As long as the make-class function returns a function that receives two parameters (one could be a list) the function can take any form.

The class function must provide all of the methods (both internal and external) of a class. The function must include a simple parser (i.e. a command recognizer) to identify a method name and to call the corresponding function, passing the parameters of that method. The make-class function also creates the instance variables of the class. These variables will exist in the function that make-class returns and can be changed in that function.

For example, consider the example test class. In the file soop.obj the make-test function is included and returns an unnamed function which represents an instance of the test class.

(define make-test
     (lambda (proc args)
                (letrec (  (var1 val1)
                ; define the instance variables here
                  (var2 val2)
                    ......
                  (varX valX)
                ; now provide the methods of the class
                  (function1 definition)
	          (function2 definition)
	            ......
	          (functionN definition)
	       )
     ; now define the function to be returned
              (lambda
	          ;  the body of the function must
	          ;  recognize calls to the methods, 
	          ;  i.e., the names of the functions
	          ;  defined in the letrec that are to
	          ;  be public.  When it recognizes a
	          ;  method, it must call the
	          ;  corresponding function and parse
	          ;  and pass the appropriate arguments.
	       ) ; end the lambda
         ) ; end the letrec
   ) ; end the external lambda

The letrec in the outer lambda defines the variables and methods that will be used in the class. There is a difference between using a letrec in the outer lambda and using it in the inner lambda. The inner lambda defines the function which is returned. What is actually returned is a closure, i.e. the function in the environment in which it was defined. The function knows the instance variables and methods of the class. Every "instance" (i.e., returned function) has its own set of instance variables and methods.

The body of the inner lambda must recognize all public methods, parse the list of parameters sent with that method, and call the corresponding local function. This inner lambda is bound to a name in the SOOP environment and there could be numerous variables in the SOOP environment bound to different copies of this inner lambda function. This realistically corresponds to numerous instances (or objects) in an environment that are created from a single class. In the SOOP environment, the outer lambda represents the class while the inner lambda represents an instance, or object, of that class.

This assignment requires the creation of a queue class. This class should have the interface given below.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                          make-queue                           ;;;
;;;                                                               ;;;
;;; An object whose elements will be removed by the same order    ;;;
;;; they are put in "first in, first out"                         ;;;
;;; Accepts the following messages.                               ;;;
;;;                                                               ;;;
;;;  type, empty?, reset..    simple messages with no arguments.  ;;;
;;;                type returns the type of object ("queue"),     ;;;
;;;                empty returns whether the array is empty, and  ;;;
;;;                reset reprints the window                      ;;;
;;;  set-name name....sets window name to "name"                  ;;;
;;;  enqueue item.....adds "item" to the end of the queue         ;;;
;;;  dequeue..........deletes the first expression from the queue ;;;
;;;  atFront..........returns the first value in the queue        ;;;
;;;  empty-all....................empties the queue               ;;;
;;;                                                               ;;;
;;;  Examples of syntax:                                          ;;;
;;; (assign que1 make-queue)                                      ;;;
;;; (send que1 enqueue 'a)                                        ;;;
;;; (send que1 enqueue 3)                                         ;;;
;;; (send que1 dequeue)                                           ;;;
;;; (assign x make-box)                                           ;;;
;;; (send x set-val send que1 atFront)                            ;;;
;;; (send que1 dequeue)                                           ;;;
;;;                                                               ;;;
;;;  The code above will first make a queue object.               ;;;
;;;  Then it will put an "a" in the queue followed by a "3".      ;;;
;;;  The item "a" will then be removed from the queue.            ;;;
;;;  In the next statement the box x will get the element at the  ;;;
;;;  front of the queue...a "3"                                   ;;;
;;;  Finally, in the last statement the "3" is removed from the queue   ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 

What to Turn in

The faculty member using this lab should fill in the details for project submission and perhaps grading details.