CS计算机代考程序代写 python javascript Java 6 OMac

6 OMac

    6.1 Introduction
    6.2 Assignment
      6.2.1 Part 1: Objects
        6.2.1.1 Internal Keywords
        6.2.1.2 Making symbols from expressions in identi�ers
        6.2.1.3 Advice on Object Implementation
        6.2.1.4 How to Use Structs
        6.2.1.5 Example
        6.2.1.6 Starter Code
      6.2.2 Part 2: Classes
        6.2.2.1 Starter Code
      6.2.3 Part 3: Question
    6.3 What to Hand In

6.1 Introduction

In the Macros assignment, we learned how to implement Racket macros through a
series of exercises. In this assignment, we’ll build a more complex and interesting
series of object systems using Racket macros yet again (hence the name “OMac”).

6.2 Assignment

This assignment consists of three parts: de�ning objects, de�ning classes, and a
short analysis question. All code for this assignment will be written in #lang
racket (though you are welcome to use the SMoL compatibility layers).

6.2.1 Part 1: Objects

You will de�ne two macros in this assignment:

object, representing an object containing �elds and methods

(object (fields [fn iv] …)
        (methods [mn imp] …))

where fn is a �eld name (symbol), mn is a method name (also a symbol), and iv
(“initial value”) and imp (“implementation”) are both expressions.

All methods are explicitly declared as functions (typically de�ned using a
lambda in place, but the function could also be de�ned outside and
referenced from inside the object).

The methods may be evaluated when the object is created or each time the
method is called, but all other values (like initial values for �elds) should be
evaluated immediately.

You may assume there is no overlap between �eld names and method names.

Finally, all methods must take at least one argument. This argument will be
the object itself. Conventionally, this argument would be called self or this
(but it doesn’t have to be). The call macro is responsible for passing the
object along as the �rst 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 �eld than a corresponding call to the same
method. Relatedly, it may actually be more confusing to students.

call, used to call methods on an object:

(call o mn args …)

where o is an object, mn is a method name (a symbol), and args … are
arguments to that method (all expressions).

If o does not have a method by the name of mn, you should raise an error. Our
stencil provides a function raise-method-not-found-exception for doing this,
which you should use by passing raise-method-not-found-exception the
invalid method name. Missing �eld errors should be handled directly by
Racket.

Note: call’s speci�cation enforces that only methods are accessible from
outside an object. Fields are effectively private, and can only be referenced by
methods from inside the object.

6.2.1.1 Internal Keywords

If you haven’t already, you will need to learn about “internal keywords”: the
purpose of the mysterious () that appears in syntax-rules. Inside these
parentheses you can name symbols that have to appear in the precisely named
places in the input. This helps you write a macro that expects the keywords fields
and methods.

Consider, for instance, the following macro:

#lang racket
(define-syntax foo
  (syntax-rules (bar baz)
    [(_ [bar x …] [baz y …])
     (begin
       (println “all the bars”)
       (println x) …
       (println “all the bazs”)
       (println y) …)]))

Replacing (bar baz) in line 2 with () makes bar and baz regular pattern variables
and they just match against anything that is in that position. However, when bar
and baz are included in the internal keywords list, those words must explicitly
appear in order for the pattern to be matched against. Thus:

#lang racket
(foo [bar 1 2] [baz 3])
(foo [bar] [baz])

are both legitimate uses of the macro foo, but:

#lang racket
(foo [baz 3])
(foo [bar])
(foo [1 2] [3 4 5])

all result in syntax errors because they don’t match any of the macro’s patterns as
they do not contain the words bar and baz in the expected places.

You can check out the racket documentation for more information.

https://dl.acm.org/citation.cfm?id=2960327
https://docs.racket-lang.org/guide/pattern-macros.html#%28part._define-syntax_and_syntax-rules%29

6.2.1.2 Making symbols from expressions in identi�ers

By adding ’ before a name that’s been bound by a macro, we can convert the
corresponding expression into symbol.

#lang racket
(define-syntax make-symbol
  (syntax-rules ()
    [(_ sym) ‘sym]))
(make-symbol hi) ; returns ‘hi

You may �nd it useful to keep this in mind as you implement object and call.

6.2.1.3 Advice on Object Implementation

There are several ways to represent objects internally. Whatever representation
you decide on, you may want to wrap it in a simple struct to ease debugging.
When you get to Part 2: Classes, you may have very similar internal
representations for classes and objects. Having classes and objects wrapped in
separate structs will help ease debugging in the event that you accidentally pass a
class where an object is expected or vice-versa.

A struct in Racket is way to de�ne a new type. See the next section for details of
how to work with structs.

It might help to think of the object form as being roughly analogous to a
JavaScript literal object (JSON).

Be careful when implementing complex constructs like objects. 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.

6.2.1.4 How to Use Structs

The basic syntax for making a struct type is: racket (struct
( …))

For instance, to de�ne a card type with suit and value, you would do: racket
(struct card (suit value))

Once you have a struct de�ned, you can create an instance with :
racket ( …)

In our card example, we could create an instance of a card like so: racket (define
four-of-hearts (card “hearts” 4))

We also get a ? predicate, which will tell us if something is an instance
of our struct: racket (card? four-of-hearts) ; #t (card? “hello”) ; #f

Finally, to access the �elds of a struct, we use an accessor :
racket (card-suit four-of-hearts) ; “hearts” (card-value four-of-hearts) ;
4

Structs have many more advanced features, but you won’t need anything beyond
these ones for this assignment.

6.2.1.5 Example

#lang racket
(define cowboy-object
  (object
   (fields [name “Timmy the Cowboy”])
   (methods
    [say-howdy-to

https://www.json.org/

     (lambda (self to)
       (string-append name ” says: Howdy ” to “!”))]
    [get-name
     (lambda (self) name)]
    [set-name
     (lambda (self x) (set! name x))])))
 
(call cowboy-object say-howdy-to “Partner”) ; returns “Timmy the Cowboy says: Howdy Partner!”

6.2.1.6 Starter Code

We’ve provided starter code for Part 1 at objects.rkt. You are free to add any other
de�nitions to this �le that you need for your implementation (for example, a
struct). However, do not edit the contents of the �le above the “do not edit” line; if
you do, you will get a zero on this part of the assignment.

We’ve also provided a stencil for your test cases at objects-tests.rkt and testing
support code at test-support.rkt.

Please read the Testing Guidelines for guidelines on how to write tests
for the Implementation assignments.

6.2.2 Part 2: Classes

In this part, we’ll upgrade from objects to classes.

You will de�ne three macros: class, used to de�ne a new class; call, used to call
methods on an class instance; and new, which creates a new instance of the given
class-name.

#lang racket
(class class-name
  (fields [fn iv] …)
  (methods [mn imp] …))
 
(new class-name)

where a class-name is represented as a symbol.

Fields and methods are just as before.

Thus, the following code should create an object that is effectively equivalent to
the one in Example:

#lang racket
(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)

You are welcome to use your object macro when de�ning classes, but are not
required to. As discussed earlier, we recommend creating a struct to wrap your
class representation.

6.2.2.1 Starter Code

http://cs.brown.edu/courses/cs173/2021/implementation-specs/omac/objects.rkt
http://cs.brown.edu/courses/cs173/2021/implementation-specs/omac/objects-tests.rkt
http://cs.brown.edu/courses/cs173/2021/implementation-specs/omac/test-support.rkt
http://cs.brown.edu/courses/cs173/2021/testing-guidelines-section.html

We’ve provided starter code for Part 2 at classes.rkt. As in Part 1, you are free to
add any other de�nitions to this �le that you need for your implementation.

If you are using your object macro in Part 2: do not import your object
macro directly from objects.rkt. Instead, you should copy your object
de�nition into your classes.rkt �le. This is necessary for autograding
purposes.

We’ve also provided a stencil for your test cases at classes-tests.rkt. This �le
imports from the test-support.rkt given in Part 1: Objects, so make sure you have
that before working on your tests.

6.2.3 Part 3: Question

Finally, give a concise, illustrative response to the following question:

Can you see why we asked you to program in Racket rather than Plait? What would
go wrong if you used Plait instead?

Hint: 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.)

6.3 What to Hand In

You will submit four �les for this assignment:

objects.rkt, which should be uploaded to the “Objects – Code” drop on
Gradescope.

classes.rkt, which should be uploaded to the “Classes – Code” drop on
Gradescope.

objects-tests.rkt, which should be uploaded to the “Objects – Tests” drop on
Gradescope.

classes-tests.rkt, which should be uploaded to the “Classes – Tests” drop on
Gradescope.

Finally, submit your answer to Part 3: Question to the “Question” drop on
Gradescope.

You can update your submissions as many times as you want before the deadline.

http://cs.brown.edu/courses/cs173/2021/implementation-specs/omac/classes.rkt
http://cs.brown.edu/courses/cs173/2021/implementation-specs/omac/classes-tests.rkt