Re: [Pyobjc-dev] [ pyobjc-Bugs-836247 ] NSWindow.contentRectForFrameRect_styleMask_ not a class meth
Brought to you by:
ronaldoussoren
From: Bob I. <bo...@re...> - 2003-11-07 18:17:06
|
On Nov 7, 2003, at 12:45 PM, b.bum wrote: > On Nov 7, 2003, at 8:20 AM, Bob Ippolito wrote: >> No, it also happens when you are just using ObjC classes from the >> Python side of the bridge. It *always* binds to the instance method, >> nomatter what, if it has one. I'm not even worried about overriding >> them from Python at the moment, just making ObjC classes usable as >> they should be. > > Right -- and that is a bug. > > "Binding" shouldn't occur until invocation except in the case where > the developer has explicitly invoked method via the unbound method > mechanism where they previously obtained a reference to the instance > or class version of a method. > > I.e. if I have... > > id foo; > > foo = ... something ...; > [foo performSelector: @selector(description)]; > > ... then the class or instance version of description will be invoked > depending on if foo is a class or instance object. That's exactly what should happen, but that's not exactly how Python works.. Basically, selectors are descriptor instances. When you get the selector-instance-turned-descriptor from the class or instance it calls __get__(self, fromInstanceOrNone, fromClass) on the selector instance (tp_descr_get from the C API). So, the selector instance needs to remember the values of fromInstanceOrNone and fromClass and return an object (perhaps itself, but maybe not) that's suitable to be introspected or called. So, when you dispatch this object, you know if it was taken from the class or an instance (b/c fromInstanceOrNone would be None if it was taken from the class). In the current PyObjC, at this point it has already decided if it's going to use a class or instance method. Before dispatch happens. If you read back a couple posts I had a mock-Python Selector class that shows how I would like the rules of the selector descriptor game to work, which should fix this bug. The thing that I think you're confused about is that it's not clearly obvious what the target of the dispatch is.. obviously if the descriptor was taken from an instance, you know you want to use the instance version. It gets more complicated if you want to make these things act more like Python objects, where you're allowed to do call instance methods off of the class directly.. see my next paragraph. >>> I.e. if you do Foo.description to grab a reference to the >>> description method of the Foo class-- which has both +description >>> and -description-- then we should be able to figure out if the class >>> or instance implementation should be invoked at the time of dispatch >>> based on what the target of the invocation is. >>> >>> There are other details that would have to be worked out. But, for >>> the most part, it would seem that this could be done in a largely >>> automatic and transparent fashion. The remaining unknowns are >>> largely arbitrary in nature because they only occur due to the >>> combined interaction of the ObjC and Python runtimes -- we are free >>> to do whatever we want. >> >> That's what I was proposing, however there is some ambiguity in >> determining the target of the invocation if and only if we allow >> SomeClass.instanceMethod(someInstance) -- but I proposed a way that >> would figure that out most of the time, by counting the number of >> arguments given if that selector exists for both the class and the >> instance, which should work in every case that doesn't use varargs >> (do any?). > > If someInstance is an instance method, then the instance > implementation should be used... if it is a class method, then use the > class implementation. This most closely mimics the ObjC runtime. I should have said SomeClass.bothInstanceAndClassMethod(someInstance) -- doing this method-from-class-using-instance-as-argument thing creates a somewhat ambiguous case. Without *counting* the number of arguments, you can't be sure whether you meant to call the instance version or the class version. My suggested behavior breaks down when the number of arguments can not be reliably counted (varags). I don't know if this actually happens or not with the bridge, and even if it did I would imagine that it would be extremely rare to find an ObjC class that implements the same varargs selector for class and instance. > If the developer specifically wants the class vs. instance version of > the method, then we should add API for querying for the one versus the > other. The API already exists on NSObject. It's currently possible but ugly and unintuitive (I didn't even know about it, after looking at PyObjC's source code for hours). My suggestion was to use: SomeClass.bothInstanceAndClassMethod.instanceMethod(...) instead of: SomeClass.pyobjc_instanceMethods.bothInstanceAndClassMethod(...) (note that this would *never* be needed if my proposed semantics were implemented, *except* in the degenerate varargs case, if that case can even exist). -bob |