Thread: [Pyobjc-dev] Mixin classes
Brought to you by:
ronaldoussoren
From: Johan R. <joh...@gm...> - 2009-05-05 14:38:10
|
I'm trying to implement the informal NSKeyValueBindingCreation protocol. I would love to make it a mixin-class so I can reuse the functionality throughout my application. Here's how I planned to do it: class NSKeyValueBindingCreation: def bind_toObject_withKeyPath_options_(self, binding, anObject, keyPath, options): ... def observeValueForKeyPath_ofObject_change_context_(self, keyPath, anObject, change, context): .... class Foo(NSObject, NSKeyValueBindingCreation): .... The problem is that my Foo class won't recognize the observiceValueForKeyPath:ofObject:change:context: message. objc.error: NSInternalInconsistencyException - <Foo: 0x35e430>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled. If I put it directly in Foo it gets recognized. Poking through the PyObjC manual I found the following lines: Multiple inheritance may be used when subclassing an Objective-C class, so long as the Objective-C class is the first base class and there is only one Objective-C base class. The Objective-C runtime does not support multiple inheritance. These mix-in classes should not contain different implementations for Objective-C methods. To achieve this behavior, Categories should be used instead. I interpret those lines as that the snippets above should work. Am I wrong? How can I, and how should I use mixin classes? |
From: Ronald O. <ron...@ma...> - 2009-05-07 05:33:36
|
Johan, On 5 May, 2009, at 16:37, Johan Rydberg wrote: > I'm trying to implement the informal NSKeyValueBindingCreation > protocol. > I would love to make it a mixin-class so I can reuse the functionality > throughout > my application. > > Here's how I planned to do it: > > class NSKeyValueBindingCreation: > def bind_toObject_withKeyPath_options_(self, binding, anObject, > keyPath, options): > ... > def observeValueForKeyPath_ofObject_change_context_(self, keyPath, > anObject, > change, > context): > .... > > class Foo(NSObject, NSKeyValueBindingCreation): > .... > > The problem is that my Foo class won't recognize the > observiceValueForKeyPath:ofObject:change:context: message. > > objc.error: NSInternalInconsistencyException - <Foo: 0x35e430>: An > -observeValueForKeyPath:ofObject:change:context: message was received > but not handled. > > > If I put it directly in Foo it gets recognized. > > Poking through the PyObjC manual I found the following lines: > > Multiple inheritance may be used when subclassing an Objective-C > class, so long as the Objective-C class is the first base class and > there > is only one Objective-C base class. The Objective-C runtime does not > support multiple inheritance. These mix-in classes should not contain > different implementations for Objective-C methods. To achieve this > behavior, Categories should be used instead. > > I interpret those lines as that the snippets above should work. > Am I wrong? Yes ;-) > > How can I, and how should I use mixin classes? You cannot do this at the moment. Mixins cannot be used to add new methods that the ObjC runtime will see. I might add this behaviour in the future, I like your usecase and this could be used to make useful common functionality available as mixin classes. Adding this will require a detailed specification and testsuite, the objc runtime doesn't support multiple-inheritance itself and hence support for mixin classes will require some tricks. I'm especially worried about getting the semantics exactly like they'd be if the base-class is a regular Python class. Ronald > > ------------------------------------------------------------------------------ > The NEW KODAK i700 Series Scanners deliver under ANY circumstances! > Your > production scanning environment may not be a perfect world - but > thanks to > Kodak, there's a perfect scanner to get the job done! With the NEW > KODAK i700 > Series Scanner you'll get full speed at 300 dpi even with all image > processing features enabled. http://p.sf.net/sfu/kodak-com > _______________________________________________ > Pyobjc-dev mailing list > Pyo...@li... > https://lists.sourceforge.net/lists/listinfo/pyobjc-dev |
From: Greg E. <gre...@ca...> - 2009-05-07 23:45:13
|
Ronald Oussoren wrote: > Mixins cannot be used to add new > methods that the ObjC runtime will see. In PyGUI I'm using the following metaclass to get a similar effect to multiple inheritance. It merges the class dicts of all the base classes before creating the class. Usage example: class PyGUI_NSWindow(NSWindow, PyGUI_NS_EventHandler): __metaclass__ = NSMultiClass ... The first base class should be an ObjC class; the rest can be ordinary Python classes. Note that this implementation results in methods in later base classes overriding those in earlier ones, which is more or less the opposite of what normally happens. If you use this technique, you might want to reverse the order of the merging. #-------------------------------------------------- from inspect import getmro def NSMultiClass(name, bases, dic): # Workaround for PyObjC classes not supporting # multiple inheritance properly. Note: MRO is # right to left across the bases. main = bases[0] dic2 = {} for mix in bases[1:]: for cls in getmro(mix)[::-1]: dic2.update(cls.__dict__) dic2.update(dic) cls = type(main)(name, (main,), dic2) return cls #-------------------------------------------------- -- Greg |
From: Ronald O. <ron...@ma...> - 2009-05-08 05:42:39
Attachments:
smime.p7s
|
On 8 May, 2009, at 1:46, Greg Ewing wrote: > Ronald Oussoren wrote: > >> Mixins cannot be used to add new methods that the ObjC runtime >> will see. > > In PyGUI I'm using the following metaclass to get a > similar effect to multiple inheritance. It merges the > class dicts of all the base classes before creating > the class. > > Usage example: > > class PyGUI_NSWindow(NSWindow, PyGUI_NS_EventHandler): > __metaclass__ = NSMultiClass > ... > > The first base class should be an ObjC class; the > rest can be ordinary Python classes. > > Note that this implementation results in methods in > later base classes overriding those in earlier ones, > which is more or less the opposite of what normally > happens. If you use this technique, you might want > to reverse the order of the merging. Wouldn't it be more useful to tweak NSMulticlass to do the updates of the class dict in the right order? Ronald > > #-------------------------------------------------- > > from inspect import getmro > > def NSMultiClass(name, bases, dic): > # Workaround for PyObjC classes not supporting > # multiple inheritance properly. Note: MRO is > # right to left across the bases. > main = bases[0] > dic2 = {} That is: for mix in bases[::-1]: > for mix in bases[1:]: > for cls in getmro(mix)[::-1]: > dic2.update(cls.__dict__) # drop the next line: > dic2.update(dic) > cls = type(main)(name, (main,), dic2) > return cls > > #-------------------------------------------------- > > -- > Greg |
From: Johan R. <joh...@gm...> - 2009-05-09 10:10:33
|
>> Note that this implementation results in methods in >> later base classes overriding those in earlier ones, >> which is more or less the opposite of what normally >> happens. If you use this technique, you might want >> to reverse the order of the merging. > > Wouldn't it be more useful to tweak NSMulticlass to do the updates of the > class dict in the right order? I suspect that this comes from the fact the the first class must be the Objective-C class. With that constrain, a mixin class wouldn't be able to override methods of the first class. |
From: Greg E. <gre...@ca...> - 2009-05-08 23:24:27
|
Ronald Oussoren wrote: > > On 8 May, 2009, at 1:46, Greg Ewing wrote: > >> If you use this technique, you might want >> to reverse the order of the merging. > > Wouldn't it be more useful to tweak NSMulticlass to do the updates of > the class dict in the right order? That's what I meant by "reverse the order of the merging". -- Greg |
From: Greg E. <gre...@ca...> - 2009-05-10 01:14:40
|
Johan Rydberg wrote: > I suspect that this comes from the fact the the first class must > be the Objective-C class. > > With that constrain, a mixin class wouldn't be able to override > methods of the first class. Yes, I think that's the reason I did it the way I did. A better idea might be to search the base classes for one that derives from NSObject and use that as the "main" class, then merge from right to left. -- Greg |