6.001/Recitation 19

Rob Speer

Contents

Problem to ponder

  • Given a list, how can you determine if it is circular or not in linear time?
  • How about a tree?

Regressing to a simpler OO system

The Project 4 OO system is fairly friendly to program with, but you'll notice that it involves a lot of backend code. The concepts of OO show up in simpler systems, and these simpler systems might be on the test.

Useful syntax: case

case compares a symbol with a list of possibilities. It seems to be particularly designed for message handling.

Here's a stupid little function that takes in the symbols 'one, 'two, or 'three and returns 1, 2, or 3, or 0 if it doesn't match any of those:

(λ (sym)
  (case sym
    ((one) 1)
    ((two) 2)
    ((three) 3)
    (else 0)))

A message handler

The fundamental properties of an OO object are that it stores state and responds to messages. We can get this with a fairly simple procedure. As an example, here's a message handler that acts like an OO version of a pair:

(define (pair car cdr)
  (λ (message)
    ((CAR) (λ () car))
    ((CDR) (λ () cdr))
    ((SET-CAR!) (λ (val) (set! car val)))
    ((SET-CDR!) (λ (val) (set! cdr val)))
    (else (error "unknown message"))))
  • How do you call a method in this system?
  • What does the environment diagram look like?

Adding self

These simple message handlers have no concept of self; they can't consider themselves as an object that can respond to messages. One way to solve that is to pass self as the first argument for every message.

  ...
  ((POP) (λ (self)
            (begin0
              ((self 'CAR) self)
              (set! car ((cdr 'CAR) cdr))
              (set! cdr ((cdr 'CDR) cdr))))
  ...

But wait. Aren't we supposed to be using the methods we provide?

  ...
  ((POP) (λ (self)
            (begin0
              (let ((my-car ((self 'CAR) self))
                    (my-cdr ((self 'CDR) self)))
              my-car
              ((self 'SET-CAR!) self ((my-cdr 'CAR) my-cdr))
              ((self 'SET-CDR!) self ((my-cdr 'CDR) my-cdr)))))
  ...


This is getting repetitive and hard to read. An ask function would be nice.

  ...
  ((POP) (λ (self)
            (begin0
              (ask self 'CAR)
              (ask self 'SET-CAR! (ask (ask self 'CDR) 'CAR))
              (ask self 'SET-CDR! (ask (ask self 'CDR) 'CDR)))
  ...
  • So let's write this wonderful ask function.

Adding inheritance

Instead of giving up when the case statement won't handle the method, pass it on to another class.

  • Is it okay to ask your superclass?
  • We can write simple inheritance inline. Examples in OO systems like this tend to use a helper function called get-method to look up superclass methods, though. What can they gain this way?

Adding IS-A

There's a few ways to do this, some more robust than others.

Back to mutation

Draw a box and pointer diagram for what happens here:

(define y 7) (define z (let ((x (list 'a (quote (b c)) y)))

           (set! y (cdr x))
           (set-cdr! x (car (cdr x)))
           x))

z


Finally, we'll talk about the problem to ponder, detecting a circular list or tree.