7.3.2 C: OMac
In this assignment, we will build a series of object systems using macros, hence the name.You’ll also get a good workout...of your knowledge of objects. Write this code in Racket, i.e., #lang racket. You are of course welcome to use the SMoL compatibility layers.
7.3.2.1 Objects
(object (fields [fn iv] ...) (methods [mn imp] ...)) (call o mn args ...)
Think of the object form as being roughly analogous to a JavaScript literal object (JSON).
There are several ways to represent objects internally. We recommend that you create a structure that stands for objects. (How many fields this has, and what they contain, is up to you. It can be richly structured or it could just be simple container.) The reason for this is, when you get to classes, you may accidentally pass classes where you intended objects or vice versa. If the two have a similar representation, then you could get very confusing output. In contrast, having explicit structures has two advantages. First, it catches confusion early. Second, in the macro you have to choose between accessors for the object and the field structures, forcing you to reflect on what should go there, thereby improving your understanding.
If a method is not found, raise an error. Field errors can be handled directly by Racket.
In this design, only methods can be accessed from outside an object; fields are effectively private, and can only be accessed by methods from inside the object. You could imagine extending it to access fields also.
Methods are explicitly declared as functions (typically defined using a lambda in place, but the function could also be defined outside and referenced from inside the object). All methods must take at least one argument; the first argument is the object itself. Conventionally, this argument would be called self or this. The call macro is responsible for passing the object along as the first parameter.
Be careful when implementing a complex construct like this. It’s possible to create an implementation that works most of the time but is subtly wrong (as in, does something undesirable). Think about how features can interact.
7.3.2.1.1 Example
(define cowboy-object (object (fields [name "Timmy the Cowboy"]) (methods [say-howdy-to (lambda (self to) (string-append name " says: Howdy " to "!"))] [get-name (lambda (self) name)] [set-name (lambda (self x) (set! name x))]))) (test (call cowboy-object say-howdy-to "Partner") "Timmy the Cowboy says: Howdy Partner!")
7.3.2.1.2 The Self Parameter
There are generally two schools of thought on handling the “self” argument. In Java, the name this is bound automatically, and does not show up in the headers. In contrast, in Python, the name is not chosen by the language, and the programmer explicitly chooses it.We could design our object macro to automatically bind a name, too. There are multiple ways of doing it in Racket using features slightly more advanced than what we’ve used in this course. The latter design arguably has less “magic”. However, it means that a method declaration always has one more field than a corresponding call to the same method. Relatedly, it may actually be more confusing to students.
7.3.2.1.3 Choice of Base Language
Can you see why we asked you to program in Racket rather than Plait? What would go wrong? Try a small experiment (you can copy most of your code over) in Plait and see for yourself. (The answer is not something simple like a missing library, but rather a bit deeper. The simplest test may not reveal it. Remember that the primary difference between the two lies in Plait’s type system.)
Be as concise as possible in your answer. You should be able to give a short, illustrative response.
7.3.2.2 Classes
(class class-name (fields [fn iv] ...) (methods [mn imp] ...)) (new class-name)
As discussed earlier, we recommend creating a structure to represent classes.
(class Cowboy (fields [name "Timmy the Cowboy"]) (methods [say-howdy-to (lambda (self to) (string-append name " says: Howdy " to "!"))] [get-name (lambda (self) name)] [set-name (lambda (self x) (set! name x))])) (new Cowboy)