[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Delegation in goops?
From: |
Alan Grover |
Subject: |
Re: Delegation in goops? |
Date: |
Sun, 19 Feb 2006 10:24:48 -0500 |
User-agent: |
Mozilla Thunderbird 1.0.6 (X11/20050716) |
Neil Jerram wrote:
> Alan Grover <address@hidden> writes:
>
>
>>Does anybody have a solution to implement delegation in goops?
>>
>>I have an object that implements the full behavior of interest. Say it's
>>an employee object.
>>
>>For whatever perverse reason, which I assure you is reasonable, I want
>>to wrap the employee in another object. And, for the most part, it will
>>act just like the employee, except in a few places. Let's say I want to
>>have the employee masquerade as the CEO. The wrapper would implement a
>>few methods like "title", "salary", etc. And, specifically, the wrapper
>>doesn't need to know what all the other methods are, or what might be
>>added later.
>>
>>Seems like a job for delegation.
>
> Sounds like a job for inheritance to me. But I'm sure you must have
> thought of that and rejected it already, so can you explain why? That
> will probably throw some more light on your objective and thinking.
Assume that an instantiated "employee" already exists in the system
(maybe via a third-party interface), so I can't just sub-class it.
Assume that I want to delegate in two different ways.
>>So, I looked at the goops MOP.
>>
>> ...
>>
>>"no-applicable-method" assumes that you will throw an exception. It does
>>not let you substitute a method of your choosing. Specifically, it's
>>result is discarded, and it appears to be approximately in the same
>>place as "compute-applicable-methods" ....
>
>
> But if you could customize no-applicable-method to return a just in
> time method, you can equally well define your fallback method using
> define-method, can't you? (Using <top> to ensure that it matches all
> possible arg types.)
That is also one of my complaints. The only meaningful specialization on
no-applicable-method is the first argument: which is the
generic-function. So, you can't specialize on a specific generic
function, and you can't specialize on the arguments to a generic function.
If no-applicable-method was defined as:
(define-method (no-applicable-method (gf <generic>) . args)
(note the "."), then I could specialize on the arguments.
Not that it would solve the problem of delegation.
> So I don't think this is a significant
> restriction.
Well, I actually replaced no-applicable-method, and wrote a cond
statement to "specialize" on the arguments.
I can't just write a single generic-function on <top>, because I want to
delegate on "all methods for class-x, except a few". So, I would have to
enumerate all of the generic functions on the delegate-class. Which I
could do at any one point in time, but somebody could add a
generic-function/method in the future.
I did come up with a limited solution. In goops, you can change the
class of an object. So, as long as you only have one place where you
want to delegate, you can construct a sub-class, and then force an
object to become the sub-class. The behavior then looks like delegation:
the new sub-class is my "wrapper" (the CEO impostor) which only need
implement a few methods, and the original class is the delagate. But, if
I "delegated" somewhere else, it would break the first delegation.
I think I could hack another solution via compute-applicable-methods (by
replacing it). When I detect that I need to delegate, I return a special
"delegate-this" method, which calls the generic-function with
appropriate arguments fixed-up. Something like:
(define-method (compute-applicable-methods (gf <generic>) args)
(if (need-to-delegate? gf args)
(make-delegate-this gf args)
(old-compute-applicable-methods gf args))
(define (make-delegate-this gf args)
(construct-correct-data-structure delegate-this))
(define-method (delegate-this gf args)
; overly simplified:
; replace-wrapper-with-delegate needs to know
; what wrapper-class needs replacement (with what)
(apply gf (map replace-wrapper-with-delegate args)))
But this all smells bad to me.