On this page:
4.1 Introduction
4.2 Assignment
4.2.1 Part 1:   Statics
4.2.1.1 Example
4.2.1.2 Starter Code
4.2.2 Part 2:   Inheritance
4.2.2.1 Starter Code
4.2.3 Part 3:   Inheritance with Statics
4.2.3.1 Starter Code
4.3 Miscellany
4.3.1 Assignment Ordering
4.3.2 A Note on Naming
4.4 What to Hand In
4 SMoLTalk

    4.1 Introduction

    4.2 Assignment

      4.2.1 Part 1: Statics

        4.2.1.1 Example

        4.2.1.2 Starter Code

      4.2.2 Part 2: Inheritance

        4.2.2.1 Starter Code

      4.2.3 Part 3: Inheritance with Statics

        4.2.3.1 Starter Code

    4.3 Miscellany

      4.3.1 Assignment Ordering

      4.3.2 A Note on Naming

    4.4 What to Hand In

4.1 Introduction

This assignment consists of three parts that build on your previous work in OMac: implementing classes with “statics”, implementing classes with inheritance, and, finally, implementing classes with both.

4.2 Assignment

For all of the parts of this assignment, your final implementations should follow the specification from OMac: Classes unless otherwise stated. Thus, your implementation file should include definitions for class, call, and new.
Your implementation does not need to define an object macro. However, just as in OMac: Classes, you are welcome to use your object macro from OMac: Objects in your implementations if you want to.

4.2.1 Part 1: Statics

In OMac: Classes, we created objects that are isolated from one other. Sometimes, however, we don’t want them to be entirely isolated. In Java and other object-oriented languages, statics introduce the distinction between fields common to all instances of a class versus those that are specific to each instance.
We will now change the syntax of the class macro to also admit statics:
#lang racket
(class cn
  (statics [stn is] ...)
  (fields [fn iv] ...)
  (methods [mn imp] ...))
but leave the rest of the syntax unchanged. Here, stn is the name of a static field (a symbol), and is (“initial value of a static”) is an expression.
Assume that the statics and instance fields have different names, so you don’t have to worry about which ones take priority over the others.

4.2.1.1 Example
#lang racket
(class Cowboy
  (statics [cowboy-count 0])
  (fields)
  (methods [mosey-into-town
            (lambda (self)
              (set! cowboy-count (+ 1 cowboy-count)))]
           [town-aint-big-enough
            (lambda (self)
              (string-append "This town ain't big enough for the "
                             (number->string cowboy-count)
                             " of us"))]))
 
(define c1 (new Cowboy))
(define c2 (new Cowboy))
 
(call c1 mosey-into-town)
(call c2 mosey-into-town)
 
(call c1 town-aint-big-enough) ; returns "This town ain't big enough for the 2 of us"
(call c2 town-aint-big-enough) ; returns "This town ain't big enough for the 2 of us"
4.2.1.2 Starter Code

We’ve set up a GitHub Classroom assignment that contains all necessary stencil code and support code (for all parts) here. Your groups should automatically match those you created for OMac.
We’ve provided starter code for Part 1 at statics.rkt.
You do not need to submit test cases for Part 1.

4.2.2 Part 2: Inheritance

In this part, we will ignore statics and instead extend our class macro from OMac: Classes with inheritance:

(class cn extends sn

  (fields [fn iv] ...)

  (methods [mn imp] ...))

where sn is a symbol representing another class (“super’s name”).
You will also need to define a pre-defined class called Root that can serve as the root class for classes that have no real parent. Root itself has no fields or methods. It also has no parent; therefore, you need to define Root explicitly rather than creating it with the class macro. This choice is intentional: it shows that some definitions may use powers that the language’s creator has but the language’s user does not.

Root is analagous to Java’s Object class, which is implicitly extended by all Java classes.

Fields of the parent class are not visible in the child class. Each class can only see its own fields. This means the same field name can be present at each level, and each of these fields is different.

If this seems confusing, what happens in Java—where all this is type-based—might confuse you even more.

Method invocation (call) looks up the method in the given object. If it is not found there, invocation chains to the parent. This repeats until the method is found or the chain reaches Root, at which point it raises an error.
There is no defined behavior for a class extending itself.
Hint: Observe that method invocation happens on objects, but classes extend classes. That means an instantiated object also needs to instantiate its own private parent object, and so on. Again, there’s a relatively easy way to do this that will work most of the time, but may fail (i.e., produce undesirable results) in rare cases. Think about how features can interact!

4.2.2.1 Starter Code

We’ve provided starter code for Part 2 at inheritance.rkt.
You do not need to submit test cases for Part 2.

4.2.3 Part 3: Inheritance with Statics

Finally, we will have both inheritance and statics! Our final syntax is
#lang racket
(class cn extends sn
  (statics [stn is] ...)
  (fields [fn iv] ...)
  (methods [mn imp] ...))
Similar to how field visibility between parents and childs is treated in Part 2: Inheritance, parent statics should be hidden from the child.
When you’re done with Part 3, you’ll have a pretty good approximation of (untyped) Java classes!

4.2.3.1 Starter Code

We’ve provided starter code for Part 3 at inheritance-with-statics.rkt.
Unlike in Part 1 and in Part 2, you will need to submit a test suite for Part 3. We’ve provided a stencil for your test cases at inheritance-with-statics-tests.rkt and testing support code at test-support.rkt.

4.3 Miscellany

The information in this section is not part of the program spec, but you may find it helpful.

4.3.1 Assignment Ordering

We have staged Inheritance with Statics by creating an intermediate deliverable in Inheritance. Other than statics, the two portions have exactly the same behavior. Some of you may find it easier to work in that order. Others may want to do it in one leap and then “subtract” out the statics portion to create a solution for Inheritance. If you feel that would be easier, you’re welcome to do it: we don’t counsel against it.

4.3.2 A Note on Naming

The name of this assignment is a riff on our SMoL languages and meant as a tribute to the great object-oriented language, Smalltalk. However, the language we have built up here is (unfortunately) not really Smalltalk: it’s much closer to an untyped version of Java. In Smalltalk, classes are objects too, enabling various operations on classes (known as reflection). Also, if every class is itself an object, and every object is an instance of a class, there can be classes whose instances are other classes; such classes are called metaclasses. This combination of ideas leads to a beautiful, almost mystical, class hierarchy that gives programmers enormous expressive power.
If you want to play with Smalltalk, check out Squeak, which is a modern implementation, or Pharo, a closely related language with lots of great features.

4.4 What to Hand In

You will submit four files for this assignment:
  • statics.rkt, inheritance.rkt, and inheritance-with-statics.rkt, which should be uploaded to the “Code” drop on Gradescope.

  • inheritance-with-statics-tests.rkt, which should be uploaded to the “Tests” drop on Gradescope.

You may also select the entire smoltalk repository to submit to both drops on Gradescope. You can update your submissions as many times as you want before the deadline. If you have a partner, you can also add them to your submission on Gradescope.
You can update your submissions as many times as you want before the deadline.