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. |