[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Tads3] 'inherited' and propNotDefined
- From: "Kevin Forchione" <kevin@xxxxxxxxxxx>
- Subject: Re: [Tads3] 'inherited' and propNotDefined
- Date: Fri, 12 Sep 2003 11:42:39 -0700
- To: <tads3@xxxxxxxxxxx>
----- Original Message -----
From: "Jesse Welton" <jwelton@pacific.mps.ohio-state.edu>
To: <tads3@v-space.org>
Sent: Friday, September 12, 2003 7:24 AM
Subject: Re: [Tads3] 'inherited' and propNotDefined
> Kevin Forchione wrote:
> >
> > That seems right to me as well. Because you've defined xyz(x) on the
object,
> > so propNotDefined() shouldn't catch it on that object.
>
> I'm still not convinced by this reasoning, but the fact that most
> folks here seem to expect this behavior is certainly an indication
> that it's probably the right way to go anyway.
>
> > If that were the case, the question then involves nested inherited() and
> > where the capture would take place. If, for instance, we have the
following:
> >
> > class A: object
> > propNotDefined(prop, [args]) //...
> > ;
> > class B: A
> > propNotInherited(prop, [args]) //...
> > xyz(x) { return inherited(x); }
> > ;
> > class C: B
> > propNotInherited(prop, [args]) //...
> > xyz(x) { return inherited(x); }
> > ;
> >
> > Now, which propNotInherited() should catch the fact that class B doesn't
> > inherit xyz(x)? If class B defines propNotInherited() then perhaps that
> > method should catch the call, but if class B *didn't* define
> > propNotInherited() then perhaps class C's propNotInherited() should
catch
> > the call.
> >
> > In a sense, I'm picturing propNotInherited() as working up the
inheritance
> > tree in a way analogous to how a throw would work its way up the call
chain,
> > with the exception that the chain would terminate at the class that
> > initiated the first inherited().
>
> This reverse-inheritance behavior strikes me as rather perverse.
Oh, I'd agree with that! But then the idea of catching a "not inherited"
situation, as opposed to a "not defined" one is rather backward. I've just
tried to follow it down it's logical (or not) conclusion.
>I
> suspect it's not actually implementable in general, either, given the
> complex inheritance relationships possible. So, would this behavior
> actually be justifiable? So far, the justification for *some* kind of
> undefined property handling seems to be insulation from a certain
> limited class of library changes. Your scenario involves a library
> with A, an extension with B, and yet another body of code with C. You
> want to allow C to be robust with respect to certain changes (method
> removals which turn out not to remove vital functionality if caught by
> C's general handler) in A, even though B is not robust to such
> changes. That's rather obscure. It also assumes that if
> propNotInherited *is* defined on both B and C, B's should take
> precedence, which is questionable.
>
>
> I have another question about all this: how do delegated calls fit in
> to all of this? We've got propNotDefined for ordinary calls. We have
> propNotInherited proposed for inherited calls. Would a third form be
> necessary? That starts getting rather messy, doesn't it? I'm
> definitely starting to think that sticking with a singe propNotDefined
> is going to be easiest to work with.
>
> Actually, I believe this consideration has given me a fairly good
> concrete example supporting the argument that propNotDefined lookup
> should begin on the target object (superclass for inherited, delegate
> for delegated). During the actor state discussion, we discussed
> shadowing proxies which would delegate undefined methods to the
> underlying actor object instead of passing control to it completely.
> Perhaps something like this:
>
> class ShadowProxy: object
> target = nil
> propNotDefined(prop, [args])
> {
> return delegated target.(prop)(args...);
> }
> ;
>
> Now, for this to be widely useful, we'd need some way to intercept
> property assignments. We don't have these, and maybe we never will.
> That's why this is only a "fairly good" example and not an absolutely
> convincing practical example. But it still provides a more concrete
> case to think about. With that in mind, suppose we have an object
> that uses propNotDefined for some other purpose. For concreteness,
> let's say error reporting.
>
> a: object
> propNotDefined(prop, [args]) { "prop not defined: <<prop>>" }
> ;
>
> p: ShadowProxy
> target = a
> ;
>
> If we call p.xyz(), we get p.propNotDefined(&xyz), which delegates to
> a.xyz(). When we find that missing, lookup of propNotDefined must
> proceed from a, not p, for correct behavior. For consistency,
> inherited lookups should proceed the same way, from the target.
>
> Of course, that all assumes a single unified propNotDefined handler.
> That does place some restrictions on flexibility of usage, but it has
> the advantage of being clean, simple, and consistent.
That's what I had in mind when I mentioned the use of propNotDefined()
earlier. Having propNotDefined invoked on the object that is missing the
defined property. Target-defined. It's clean, simple, consistent, as you
say.
But a propNotInherited(), to me, would seem to make more sense as a
caller-defined method, which as you point out, is reverse-inheritance and
convoluted.
--Kevin