3 Objects
3.1 Introduction
In this assignment you will implement the Standard Model of Objects. Though there are many things that languages with objects disagree about, there is some essential commonality, and (a stripped-down version of) that is what you will build.
3.2 Assignment
You are again given a parser,
parse :: S-Exp -> Expr |
which now contains some additional language conveniences. Your task is to extend the function
interp :: Expr -> Value |
to include the features described below.
You should implement objects as a new kind of value in the language.
You should consider representing the collection of methods in an object as a Hashof mapping names to the method definitions.
You may find it useful to look up and, if necessary, implement functions like map and zip.
3.3 Features to Implement
3.3.1 Non-Flat Environments
For simplicity, in Interpreter, we had just a single “flat” environment, which worked through functional update. Note that this is not how the environment appears in the Stacker!
From now on, we want you to manage the environment in a way that better represents the reality of programming language implementations: as a sequence of “frames”. Each frame is an association of the local names to their values, and the sequence reflects the nested scopes, with the deepest scope first and farthest scope (such as the global scope) last. This will now match the way the environment looks in the Stacker.
As a matter of implementation in plait, we use lists for the stack and
hashes for each frame, so the type of Env will be (Listof
(Hashof Symbol Value)). Please be careful to not confuse this
sequence of frames—
3.3.2 Multi-Arity Lambda
Until now, in Paret, Functions took only one argument. Now we generalize them to permit zero or more arguments. A function call (e-app) must have exactly as many arguments as the function declaration (e-lam) has; otherwise, signal an error.
3.3.3 Objects
They can have many function bodies. Each one is given a different method name and its corresponding parameters.Correspondingly, lambda can be thought of as having only a single method. Hence, it does not need a name to tell apart the different methods, and can be applied directly.
Every method must have at least one argument, in the first position. It can be called anything (though it is conventional to call it self or this). Its value is the object that was evaluated at the method call (e-call) from which this method was obtained.
evaluate the o expression,
confirm that it is an object (and error otherwise),
look for m in that object (and error if it doesn’t have a method by that name), then
invoke m with (in this case) two arguments, the value of o as the first argument and the value of x as the second one.
In particular, then, note that that in our design—
3.4 Grammar
<expr> ::= ... # minus function definition and call |
| (lam (<var> ...) <expr>) # function definition |
| (<expr> <expr> ...) # function call |
| (object [<symbol> (<var> <var> ...) <expr>] ...) # method definition |
| (call <expr> <symbol> <expr> ...) # method call |
3.5 Abstract Syntax
The definition of Expr is as follows:
(define-type Expr |
(e-num [value : Number]) |
(e-str [value : String]) |
(e-bool [value : Boolean]) |
(e-op [op : Operator] |
[left : Expr] |
[right : Expr]) |
(e-if [condition : Expr] |
[consq : Expr] |
[altern : Expr]) |
(e-lam [params : (Listof Symbol)] |
[body : Expr]) |
(e-app [func : Expr] |
[arg : (Listof Expr)]) |
(e-var [name : Symbol]) |
(e-obj [methods : (Hashof Symbol Method)]) |
(e-call [obj : Expr] [method : Symbol] [args : (Listof Expr)])) |
3.6 Starter Code
See GitHub Classroom.
3.7 What To Hand In
You will submit to two Gradescope drops for this assignment:
objects.rkt, which should be uploaded to the “Code” drop on Gradescope.
objects-tests.rkt, which should be uploaded to the “Tests” drop on Gradescope.