Re: [Pyobjc-dev] Controller Layer
Brought to you by:
ronaldoussoren
From: Ronald O. <ous...@ci...> - 2003-12-24 23:54:38
|
On 24 dec 2003, at 20:38, b.bum wrote: > On Dec 23, 2003, at 5:00 PM, Ronald Oussoren wrote: >> For some reason the instance of 'Converter' is an instance of >> 'NSNotifying_Converter' during the call to 'getAmount', and >> 'getAmount' is not recognized as a Python method which is causing >> infinite recursion. The class of the object is probably changed to >> implement some feature of KVO. > > That is exactly what is happening. As others have discovered, > automatic KVO works leveraging posing type behavior to override the > setters and getters such that change notification can be automated. > > Somewhat evil, yes, but it is efficient and transparent in the case > where you aren't playing intense games with the runtime (as does > PyObjC). It's not necessarily 'evil', just exploiting the dynamic nature of the ObjC runtime. PyObjC incorrectly assumes that nobody will play such games, and that is a, fixable, bug. > >> This is fixable by using libffi more agressively, although this may >> have other negative effects. E.g., we should use libffi to find the >> exact Python function to the method stub, instead of looking up the >> Python method in the class when it is called. > > This would defeat the dynamic dispatch inherit to both objc and > python, correct? I.e. if I write... Not really. The ObjC method dispatch table currently contains a method-stub that dispatches again to find the Python callable that actually implements the method, basically: id imp_foo(id self, SEL _meth, ...) { PyObject* selfObj; PyObject* methObj; selfObj = PyObjC_IdToPython(self); methObj = PyObject_GetAttrString(selfObj, (char*)_meth); // Gather the arguments in a tuple and call 'methObj' } By using libffi even more than we do now we can basically pass the 'methObj' as an extra argument to 'imp_foo'. That way we loose one level of dynamic dispatch, which could be slightly faster. If this is implemented correctly the user of PyObjC won't notice a thing (other than KVO not crashing anymore). I've done a quick test and this actually works, I'm going to work on the correct implementation of this. > > x.doSomething() > y.editTheRuntime() > x.doSomething() > > ... and editTheRuntime() does exactly that, then the second invocation > could lead to a completely different implementation of doSomething(). This might not even work with the current implementation, if Python methods get replaced in C code the Python side won't pick up the changes. I'll look into this as well :-) > > KVO is somewhat misnamed -- it isn't limited to key/value coding. > That is the whole point behind doing some relatively low level edits > to the runtime to make KVO work the way it does. By doing so, it > breaks the dependency on the developer always changing the value > through the NSKeyValueCoding methods, thus making change observation > transparent to the usage of the class (as long as the developer uses > the setters and getters, directly or indirectly, the changes will be > observed). > > Could the existing functionality be modified such that the presence of > the notifying posed class does not break the dispatch into Python? See above. The interesting question: should the __setattr__ of Objective-C objects implement KVO? E.g. should 'self.foo = bar' notify observers or should we rely on accessors. I'd say that the assignment should notify observers, especially because accessors are not necessary to be able to use KeyValueCoding. Ronald |