[plt-scheme] PLT Object System

From: Richard Cobbe (cobbe at ccs.neu.edu)
Date: Sun Feb 20 12:24:06 EST 2005

On Sun, Feb 20, 2005 at 11:19:57AM -0500, David J. Neu wrote:

> Hi,
> 
> I have a question about the PLT object system ...

<SNIP>

> Now similarly, suppose you'd like to define a class to have a GET and
> a SET procedure for a variable, and that you'd like to be able to
> "override" these procedures on a one-time basis without bothering to
> derive a new class.
> 
> The example below works up until the last line:
> 
> (require (lib "class.ss"))
> 
>  (define foo%
>    (class object%
>      (init-field x
>                  (get (lambda () x))
>                  (set (lambda (_x) (set! x _x))))
>      (set x)
>      (super-new)))
> 
> (define bar (new foo% (x 2)))
> (display (get-field x bar)) (newline)
> 
> (define barbar (new foo% (x 2) (get (lambda () (add1 x)))))
> (display (send get x barbar)) (newline) ;; FAILS - no GET method
           ~~~~~~~~~~~~~~~~~~~

I'm assuming you meant (send barbar get) here, but that's not the
problem.

(Further, it's not obvious to me what the (set x) expression in your
definition of foo% does, but again, I don't think this is relevant.)

> It seems that their is a differentiation between fields and methods
> that does not exist in "the rest" of Scheme, so the idiom used to
> parametrize a procedure in my first example doesn't work.

That's correct, yes.  (IIRC, in an earlier class system, a method was
just a field whose value was a function.  That went away with either
v200 or v100, I don't remember which.)

> Is there a way to do this?

It's verbose, but you can do this by adding a level of indirection:

(define foo%
  (class object%
    (init-field x
                (_get (lambda (x) x))
                (_set (lambda (_x) (set! x _x))))
    
    (define/public get (lambda () (_get x)))
    (define/public set (lambda (x) (_set x)))
    
    (super-new)))

> (define bar (new foo% [x 2]))
> (get-field x bar)
2
> (send bar get)
2
> (define bar2 (new foo% [x 2] [_get add1]))
> (get-field x bar)
2
> (get-field x bar2)
2
> (send bar2 get)
3

Note that I had to change your interface slightly; the _get init arg now
takes one parameter.  Otherwise, you'd have to do something like this

    (define bar3 (new foo% [x 2] [_get (lambda () (add1 x))]))

which doesn't work, because x isn't bound in this expression.

> Do generics have a role?

I didn't actually try this, but I don't think they'll help.  According
to the manual (in 299.31), generics only allow access to methods, and
neither get nor set is a method in your original definition of foo%.  I
could be completely wrong here, though.

And while my solution works, there may well be other alternatives.

Richard



Posted on the users mailing list.