[racket] Declarative Prototype Object Extension - looking for feedback
On 01/23/2013 08:57 AM, Lewis wrote:
> I'd always found prototype object systems interesting, and thought
> they might be a good fit for racket - so I made one about a month or
> so ago
>
> Features:
> - Prototype based, no distinction between classes and instances.
> - Multiple inheritance, methods are looked up in depth first search
> - Declarative syntax, can create an object with a single macro, no need to clone
> and mutate
> - Immutable objects, which can be inherited by and inherit from mutable ones
>
> https://gist.github.com/4605785 - go to line 195 shows its usage.
>
> Basically, I am after feedback on my code, the concept in general, and
> anything really. I actually use it over the java-style class object
> system racket has, it's very much my vision of what objects should be
> like. But yes, any feedback would be welcome.
It looks good. Here are a couple comments:
You use 'syntax-local-introduce' and 'syntax-local-get-shadower' to bind
'self', whereas it would be simpler to use syntax-parameters. Look at
"Keeping it Clean with Syntax Parameters". (You are already avoiding
many of the problems of other unhygienic approaches by using
'syntax-local-get-shadower'... but syntax parameters put a nicer
interface on it.)
Your struct definition for 'immutable-object' isn't used anywhere, so
perhaps it's leftover from previous experiments code, but its
declaration of a 'parents' field doesn't change the inherited field
'parents' from being mutable to immutable; it just adds another one.
AFAIK, there's no simple way to have immutable and mutable variants of a
struct type where immutability is enforced by Racket without some kind
of indirection. By indirection I mean something like the hash: you use
mutable hashes for mutable objects and immutable hashes for immutable
objects. But it's harder for the parents fields. In the past when I've
hit this problem I've just defined two variants and handled them
separately (possibly with a super-struct with some shared fields), but
I'm not thrilled with that solution either.
Finally, it looks like your lookup operation (the prop:procedure handler
and the 'lookup' helper) don't distinguish between "I found the key
(msg), and its value is null" and "I didn't find the key". And the
recomputation of (p msg) in 'lookup' looks like it could make getting a
property take time exponential in the length of the parent chain to the
property.
Ryan