[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: