Re: [Pyobjc-dev] More on integer values
Brought to you by:
ronaldoussoren
From: Ronald O. <ous...@ci...> - 2003-02-03 15:56:17
|
On Monday, Feb 3, 2003, at 15:02 Europe/Amsterdam, bb...@ma... wrote: > We need unit tests. David: do you have a test case that > demonstrates the mishandling of integers with NSUndoManager? > > If you could send it to me, I will integrate it into the > test_nsundomanager.py in Lib/Foundation/test/. > > A unit test demonstrating the problem will ensure that we are all > talking about the problem using the same vocabulary and expectations. > > On Monday, Feb 3, 2003, at 02:13 US/Eastern, Ronald Oussoren wrote: >> Not too hard. There are (at least) two possible solutions: >> >> - David could use objc.selector to specify a signature that is more >> to its liking (e.g. one of the >> arguments is an int instead of an object). I don't really like >> this, mostly because of the arcane >> interface of selector() > > Wouldn't this require applying the objc.selector() to the undo > manager? That seems problematic for a number of reasons. Of > course, if David were to subclass NSUndoManager and apply the > objc.selector() calls to that subclass, it wouldn't be a problem. > > I.e.: > > class FundoManager(NSUndoManager): > setColorCount_ = objc.selector(None, selector="setColorCount:", > signature="v@:i") > It wouldn't be necessary, from what I understand the NSUndoManager will forward calls to methodSignatureForSelector: to the current target, e.g. you have to use the call to selector in the class that defines 'setColurCount:'. > If that is the case, it is a bummer, but not altogether too ugly save > for the 'signature' argument. If we were to declare a handful of our > own types, the signature could be defined as an array of type objects. > Something like: > > signature = [VoidType, IDType, SelectorType, IntType] > > Actually, it really should be two different arguments to selector(): > > objc.selector(None, selector="setColorCount:", > returnType=VoidType, argumentTypes=[IntType]) > > We can drop the IDType and SelectorType specs because every selector > must take (id) and (SEL) as the first two arguments. You can already use a variation on this theme: use 'return_type' and 'argument_types'. Both are specified using a subset of the Py_BuildValue syntax, argument_types should not describe self and _cmd. I prefer this to your proposal because Py_BuildValue will be familiar to at least some python programmers. BTW. We do have documentation for this (-: >>> import objc >>> help(objc.selector) Help on class selector in module objc: class selector(__builtin__.object) | selector(function, [, signature] [, selector] [, class_method=0] | [, return_type] [, argument_types] [, required=True]) -> selector | | Return an Objective-C method from a function. The other arguments | specify attributes of the Objective-C method. | | function: | A function object with at least one argument. The first argument will | be used to pass 'self'. This argument may be non when defineing an | informal_protocol object. | selector: | The name of the Objective-C method. The default value of this | attribute is the name of the function, with all underscores replaced | by colons. | signature: | Method signature for the Objective-C method. This should be a raw | Objective-C method signature, including specifications for 'self' and | '_cmd'. The default value a signature that describes a method with | arguments of type 'id' and a return-value of the same type. | argument_types, return_type: | Alternative method for specifying the method signature. Return_type is | return type and argument_types describes the list of arguments. The | return_type is optional and defaults to 'void' (e.g. no return value). | Both are specified using a subset of the Py_BuildValue syntax: | - s, z, S: an NSString (id) | - b: a byte (char) | - h: a short integer (short int) | - i: an integer (int) | - l: a long integer (long int) | - c: a single character (char) | - f: a single precision float (float) | - d: a double precision float (double) | - O: any object (id) | It is not allowed to specify both 'argument_types' and 'signature' | class_method: | True if the method is a class method, false otherwiserequired: | True if this is a required method in an informal protocol, false | otherwise. The default value is 'True'. This argument is only used | when defining an 'informal_protocol' object. | > >> - We could treat NSNumber like a Python number when translating >> arguments to Objective-C values. Doing >> that would not be too hard. Or we could translate NSNumbers to >> Python numbers when translating from >> Objective-C values to Python values, but I don't think we should do >> that. > > [For the following, the exact same discussion could be applied to > floats/doubles] > > There are two distinct problems associated with handling integer types > as a result of their being three different means of encapsulating an > integer within a PyObjC based application. There is the native C > (int) type, a Python IntType, and NSValue/NSNumber instances. > > The first problem is associated with converting (int) to Python > IntTypes and back. This generally works fine in the current code > base. Where it falls apart is in cases like the one David is > describing with NSUndoManager. That is, when a method that takes an > integer argument is invoked through the bridge against a proxy object > that does not contain the signature of the method to be invoked. That is not a problem with the bridge, but in the way it is used: The bridge cannot know that the user expects an int/float instead of an object unless it is told so. > > If the aforementioned potential fix doesn't work, I'm not sure what > will. > > The second problem involves the bridging of NSNumber into Python > numbers and vice versa. Currently, this doesn't appear to be broken. > It is also not an issue in the context of David's problem. There > may be some subtleties that could be cleaned up in this context, > though. As mentioned in the "autobridging by conversion" message, it > may be useful to create a custom subclass of NSValue that can > encapsulate the various Python number types. This would allow us to > preserve the python instance when a number comes back across the > bridge. Not only does this increase transparency of the bridge, but > it may also reduce memory footprint and increase performance [in that > we would just recycle the python instance coming back]. This *is* a problem in the context of David's problem. He is passing an object ("coincidently" an Python int) through the Objective-C runtime from Python to Python. In the process this object is translated into a completely different object. We could automaticly translate NSNumber objects to Python numbers, that would solve most, if not all, problems with passing numbers 'through' Objective-C. However, this is not entirely trivial: You must take care to extract the right kind of basic type from the NSNumber otherwise you'd loose information. BTW. If we do this some of the unit tests will fail (those that abuse NSArray to create NSNumber objects). Hmm, that is not really a problem: NSNumber objects would completely disappear from user code. Ronald |