Re: [Modeling-users] inheritance and relations confusion
Status: Abandoned
Brought to you by:
sbigaret
|
From: Mario R. <ma...@ru...> - 2003-11-16 23:15:28
|
Hi,
thanks for taking the time to clarify this issue... given that it seems=20=
that
others are not often surprised by this, and that making this automatic
will result in unnecessary overhead, I would be in favour of just=20
clarifying
when this may happen, and how to deal with it (also in the form of a
nice faq...)
Having said this, I still do not fully buy the performance overhead
argument. See comments below...
> Hi all,
>
> Back on the subject, now that the problem is identified. I think =
this
> can be interesting to anyone willing to understand faults and the way
> they are handled by the framework, so I'll try there to be as explicit
> as possible. This message concludes with... a question on how this=20
> could
> possibly be handled by the framework in the future, your opinion is
> appreciated.
>
> Remember we have a model: A <<----> B, with B inheriting from A, and =
we
> have an two instances 'a' and 'b' in relation to each other: a <<---->=20=
> b
>
> you fetch object 'a':
>
>>>> a=3Dec.fetch(..., isDeep=3D1)[0]
>>>> b=3Da.getB()
>
> Now, if we suppose that the fetch only fetched 'a' and *not* 'b' as=20
> well
> (which is possible since the fetch has isDeep=3D1), assuming =
furthermore
> that b has not been fetched before within 'ec', we have:
>
>>>> b.isFault()
> 1
>>>> b, b.__class__
> (<A.A instance at 0x820b24c>, <class A.A at 0x81d7f6c>)
>>>> b.getAs
> [...]
> AttributeError: A instance has no attribute 'getAs'
>
> --> b is a faulted object, and indeed, its class is A; like any fault,
> its class is the root entity's class. That is basically why you =
get
> an AttributeError when trying to send to this object a 'getAs()'
> message, to which only class B's instances can answer.
In this particular model, it is categoric that an A is related to a B=20
(or,
I guess, a sub-class of B, but not a super-class of B!).
So, I still do not see why an A is returned, as this does not
conform to the model -- thus I see this as incorrect behaviour.
> Now if you clear the fault (b.willRead()), then b.getAs() works as
> expected.
Fine. At the moment, the (default) code that gets executed when
a.getB() is called is something like:
def getB(self):
"Return the b relationship (toOne)"
self.willRead()
return self._b
But, what's wrong with doing something like (only when an entity
participates in an inheritance hierarchy) ?
def getB(self):
"Return the b relationship (toOne)"
self.willRead()
b =3D self._b
b.willRead()
return b
This method is not called all the time b needs to be accessed (as in
the examples you cite below, right?), so the performance hit (associated
with the _getattr_ suggestion) is minimal. Or am I being too naive here?
> I understand this can be surprising. The fact is that the model here
> is very simple, and that you expect to get a B instance, not an A. =
To
> understand why a fault is *always* an instance of the root entity=20
> when
> created, just imagine there is a third entity in the model such as:
>
> C <<-----> A <<----> B
>
> and an object 'c' such as: c <---> b <----> a
>
> If you fetch c first, then getA() returns 'b', a fault for an 'A',
> then you fetch 'a', and you expect to get the _same_ object 'b' when
> you ask for a.getB() --this is uniquing: the same row can only be
> represented by one, and only one, object in the editing context.
> As you can see here, even by examining the model there is no way to
> deduce from it that 'b' will be a 'B' when we ask for c.getA() --and
> I'm sure we do not want the fault's class to be checked and=20
> eventually
> changed when a is asked for getB(), or we'll experiment a real slow
> down in the process of uniquing & fetching objects.
Other than the a.getB() explicit calls in client code, when is this
method called within the framework?
> I hope I succeeded in making it clear /why/ faults are created w/ the
> rott entity's class. Now it can be also surprising that the fault is=20=
> not
> automatically cleared when it gets the 'getAs()' message. In fact, =
this
> is not a bug in itself, the fault is just not programmed to act like
> this.
>
> There would be a way to do this: define __getattr__() so that it=20
> calls
> willRead() on the object when it gets called. But this is not
> something I want to add to the default behaviour, I do not think =
this
> is a good thing to do, just because __getattr__ gets called in a lot
> of situations where you do want a fault to be actually triggered. =
For
> example, asking 'dir(b)' makes __getattr__ be asked for =
'__members__'
> and '__methods__', printing 'b' (in log e.g, or wherever) makes
> __getattr__ be asked for '__str__', then for '__repr__' (when none =
of
> them exists and before falling back to the default --clasic-style
> classes only), etc.
>
> --> I'm pretty sure that, if this is made the default, almost everyone
> will complain sooner or later about faults being triggered for
> choose-any-reason-here...
>
> That's the reason why this is not the default, and why the choice=20=
> is
> left to each developer there.
>
> Now, of course, __getattr__ could be designed so that it only calls
> willRead() if any of the class' subclasses methods are searched...
> Should we go that way? Or does anyone see an other possible =
approach?
> Or maybe is it enough to explicitely add this to the documentation?
Again, it seems that few fall into this surprise, so attempting a=20
possibly
bug-prone complex solution may not be worth the effort. I would be happy
just to be aware of what is happening, so I know how to deal with the
situation. If there is a simple way to unfault objects when needed, then
so much the better.
Cheers, mario
> -- S=E9bastien.
|