[racket] Functional struct update with subtypes

From: Mark Engelberg (mark.engelberg at gmail.com)
Date: Wed May 11 20:32:17 EDT 2011

On Wed, May 11, 2011 at 1:10 PM, David Van Horn <dvanhorn at ccs.neu.edu> wrote:
> Here are some struct definitions and a function, based on Land of Lisp:
>
> (struct monster (id [hit #:mutable]) #:transparent)
> (struct orc monster (club) #:transparent)
> (struct hydra monster () #:transparent)
> (struct slime monster (sliminess) #:transparent)
> (struct brigand monster () #:transparent)
>
> (define (damage! m n)
>  (set-monster-hit! m (max 0 (- (monster-hit m) n))))

I'd like to be proven wrong, but I really think you have to use OO
techniques to achieve this kind of polymorphism in Racket.

I wrote Land of Lisp's orc battle in a few different ways, exploring
stylistic variations using Racket's class system, which I had never
used before.  In one version, I made all the "fields" private, e.g.,
with (define agility 30), and then explicitly made getter and setter
methods.  In another version, I specifically used the field construct,
e.g., (field [agility 30]) so I wouldn't have to write the getter and
setter methods.

I wasn't entirely happy with either version.  I felt that the code
would have been much cleaner if there were some sort of analog to
"protected" fields and methods, in which the subclasses could see the
fields and methods but outside classes could not.  The
private-with-accessors version was rather verbose.  On the other hand,
when working up the field version, I felt the code was somewhat
klunky; I was frequently tripped up by the fact that field accessors
place the field name first and object second, whereas send places the
object first and the method second.   Furthermore, fields have their
own verbosity -- overriding the initialization of a field in a
subclass is a two-step process, for example, and you end up with a lot
of inherit-field statements if you want to access fields in a manner
that's consistent with new fields.

Ultimately, I decided that the field version was the cleaner of the
two, but I remain interested in seeing if there is a better way to
code it using Racket's constructs.

If you're curious, I can send you my code samples off-list.



Posted on the users mailing list.