[Prev][Next][Index][Thread]
Re: [Q]Why are all classes rooted by <object>
On Sat, 4 Aug 2001 11:30:02 -0400 (EDT), "Eric Kidd" <eric.kidd@pobox.com>
wrote:
> In article <04lzvud73001-2907010803140001@jump-x2-0132.jumpnet.com>, "Tim
> Olson" <04lzvud73001@sneakemail.com> wrote:
> > Is there a standard "clean" way of wrapping a Dylan object in a proxy
> > object? In Smalltalk, the standard way is to create a new subclass of
> > "nil" (instead of "Object"), which means it inherits no implementation
> > whatsoever. Then a single method "doesNotUnderstand:" is implemented in
> > that proxy class, which intercepts all messages sent to the proxy object
> > and sends them on to the wrapped object.
> >
> > But with Dylan's multi-dispatch and a fixed root class of Object, this
> > trick doesn't work.
>
> This works nicely in weakly-typed, message-passing languages. For example,
> in SmallTalk, Perl or Python you can treat any object that defines a
> particular set of methods as being a member of a "type".
>
> In C++, Java and Dylan, however, the language actually cares about the
> class hiearchy when dispatching method calls. So simple delegation is
> broken pretty much from the get-go, long before you get to issues of
> single-rootedness or generic functions.
Actually JDK 1.3 has a new Proxy class which goes someway towards allowing
you to build delegators more easily.
BTW Here is what I said last year on this topic (courtesy of dejanews):
> As the others have pointed out, Dylan doesn't have this kind of technology. In
> part this is because Dylan doesn't use message-passing OO, but instead uses
> generic-function OO. With message-passing there is a principle object which you
> can query, but with generic functions there isn't.
>
> As Hugh hints, if the error class were better defined one could catch the error
> and retry via some delegate function. Eg untested pseudo code:
>
> define macro with-delegation
> { with-delegation ()
> ?body:body
> end; }
> =>
> { block
> ?body
> exception ( e :: <no-applicable-method> )
> delegate( e.arguments.first, e );
> end; }
> end macro;
>
> Then you could define a delegate method specializing on your proxy class that
> trampolines to an inner object, eg
>
> define method delegate
> ( object :: <proxy>, except :: <no-applicable-methods> )
> apply( except.function, except.args.first.inner, except.args.but-first );
> end method;
>
> And the default delegate method would be:
>
> define method delegate
> ( object :: <object>, except :: <no-applicable-methods> )
> error( except );
> end method;
>
> This glosses over a lot of issues, but you get the idea.
>
> --
>
> The conventional way of doing proxy forwarding in Dylan is to define a proxy
> mixin for the methods that you want. Then you can inherit this anywhere you
> want to an only bother overriding the methods each class cares about.
>
> eg
>
> // framework class holds next in chain of delegates
>
> define abstract class <proxy> ( <object> )
> slot next :: <object> = #f, init-keyword: next:;
> end class;
>
> // you define your proxy class that forwards all its methods to its delegate
>
> define class <foo-proxy> ( <proxy> )
> end class;
>
> define method bar ( x :: <foo-proxy>, ... )
> bar( next( x ), ... );
> end method;
>
> define method baz ( x :: <foo-proxy>, ... )
> baz( next( x ), ... );
> end method;
>
> // you can then define other classes that act as proxies for this kind of
> // object by just mixing in the proxy class and overriding the methods you want
>
> define class <quux> ( ... <foo-proxy> )
> end class;
>
> define method bar ( x :: <quux>, ... )
> ...
> end method;
>
> It is still labourious to define the proxy class though and it doesn't
> automatically deal with new methods.
>
> Ultimately you could move up a level an reify your function calls as objects in
> their own right, then you could invoke them and delegate them as you wished. In
> theory, you could still hide all this in function call syntax via macros.
>
> Eg
>
> define macro foo
> { foo( ?x:expression, ?y:* ) }
> =>
> { delegate( foo, ?x, ?y ) }
> end macro;
>
> define method delegate ( f :: <function>, x :: <bar>, ... )
> f( x.next, ... );
> end method;
>
> Or some such...
__Jason
References: