[Pyobjc-dev] Re: [Pythonmac-SIG] pyobjc / cocoa

bbum@mac.com bbum@mac.com
Wed, 16 Oct 2002 11:34:47 -0400


(Jack;  thanks for the CC to pyobjc.  I have now subscribed to 
pythonmac and will try to keep up with things in this SIG.)

First, a brief update on the progress made on the PyObjC project.

The module itself is now compatible with the Apple supplied build of 
Python 2.2.

At this point, the developer can create a new project in Project 
Builder, select "Cocoa-Python Application" (a custom template included 
with PyObjC), and Project Builder will create a new Cocoa application 
project that is implemented entirely in Python.  The project template 
includes an implementation for a basic application delegate (NSObject 
subclass) that includes target/actions, outlets, and notification 
handling.

When the 'install' target is used, the resulting application runs 
completely standalone on any OS X 10.2 machine without requiring that 
the user has preinstalled PyObjC or a custom build of Python.

In comparison to Cocoa-Java, the PyObjC bridge is significantly less 
intrusive.   More on this below.

In comparison to Cocoa-AppleScript (AppleScript Studio), the PyObjC 
bridge presents a development experience that is much closer to pure 
Cocoa.  AppleScript Studio is really a mix of Cocoa widgets into 
AppleScript style event handling-- the end result is very powerful, but 
it isn't Cooca programming.

At this point, the PyObjC bridge is being used in several production 
quality projects/products.  I.e. it is working now and working 
extremely well!!

(And, again, a huge note of thanks to Ronald -- his work on the 
subclassing and method dispatch mechanisms made it all possible.)

More information interspersed with Jack's and Ronald's text below.

On Wednesday, October 16, 2002, at 09:17 AM, Jack Jansen wrote:
> [I've added pyobjc-dev to the distribution]
> On Wednesday, October 16, 2002, at 02:28 , Ronald Oussoren wrote:
>>> Something that is open to discussion, I think, is how to map ObjC 
>>> names to Python names. The current PyObjC code supports two 
>>> compile-time options, object.message_withFoo_(arg1, arg2) and 
>>> another that I forget with even more underscores in there (this 
>>> mapping is ambiguous: it maps to both [object message: withFoo:] and 
>>> to [object message_withFoo:]). The Java-ObjC brigde has simply 
>>> defined sensible static mappings for all names used in Cocoa, and 
>>> the above would probably become something like 
>>> object.messagewithFoo() or object.messageWithFoo(). Python's current 
>>> method is more flexible, but boy does it lead to ugly method names 
>>> in your code...
>>
>> Changing the mapping from Objective-C names to/from Python names is 
>> definitely open for discusion.
>>
>> BTW. The current PyObjC no longer supports object.message__withFoo__.

We have been down this path a number of times over the six year history 
of the PyObjC module.  In all cases, we have ended up back with the 
naming conventions that we have now for a number of reasons.   Moving 
from double underbar to single underbar was definitely a win -- made 
the code easier to read and write.

> I think that what I would like is one static scheme that is the same 
> (or almost the same) as the Java/ObjC naming scheme, plus a fallback 
> scheme (which could be the current message_withFoo_ scheme). There may 
> be a problem here with overloading, though: if I look at AppKitJava 
> there's often multiple ObjC selectors that map to one Java method 
> name, I'm not sure how they handle this, especially in the face of 
> overriding ObjC methods from Java.

The key value in the PyObjC module is that it provides an ObjC 
development experience that is about as close to transparent as can be 
achieved when mapping from one language to another.   One of the most 
frustrating aspects of doing ObjC/Java (the bridge existed back to 
WebObjects 3.0 in 1997) was because of the mapping of method names.  
Specifically, the developer effectively had to learn three APIs deeply 
to be effective -- the ObjC API, the Java SDK APIs, and this weird 
permutation of the ObjC APIs as presented in Java.

End result;  the developer is constantly frustrated by constantly 
having to do the mapping in their heads.  Worse, the mapped 
representation -- the conversion from, say, setObject:forKey: to 
setObjectForKey() -- loses the emphasis on the number and order of 
parameters that is emphasized by ObjC's method naming scheme.

 From personal experience-- both as a developer and a WebObjects 
training instructor-- I can confidently say that all of the effort that 
was put into presenting the ObjC API in Java such that it appeared to 
be a Java API caused a hell of a lot more confusion than it ever 
perpetuated clarity!

Even if it slightly less Python-Pretty, this...

     mutableDictionary.setObject_forKey_ ( "foo", "bar" )

... is ultimately easier to read and maintain than this...

     mutableDictionary.setObjectForKey( "foo", "bar" )

... for a number of reasons:

     - the first is immediately recognizable as an ObjC method call.  
Regardless of how transparent the bridge is, the bridge is there and it 
does affect behavior.  Trying to hide it makes maintenance 
significantly more expensive and the introduction of new developers 
into a project harder.  (I helped maintain a mixed ObjC<->Java codebase 
with 500,000+ lines of code for over 3 years.   The bridge was the 
single largest cause of problems in the project -- that it tried to 
hide the "crossing of the bridge" just confused things.)

     - the first form preserves the argumentation information as 
provided by the traditional ObjC method name (setObject:forKey:)-- the 
developer can easily map between that syntax and the original ObjC 
method.  The second loses that information and the developer can easily 
assume that the key should be first.   This is a huge problem among my 
development team with WebObjects 5.x -- all of us make this kind of 
mistake on a regular basis.

     - the first has the distinct advantage of allowing the developer to 
*always* be able to deduce the original ObjC method name by simply 
looking at the code.  The developer doesn't have to go follow some 
random mapping to try and figure out what the ObjC method's name 
originally was.

> Hmm, even if that isn't possible we could cop out: if the method name 
> translation routine finds that a certain name isn't in the 
> dictionaries it would simply add it. Or (more cumbersome, but safer) 
> there could be a (Python) API MapObjCSelector('message:withFoo', 
> 'messageWithFoo') which could then also check that this mapping 
> doesn't conflict with another one. With such a scheme the Python 
> programmer would have to declare any new ObjC messages it uses, but 
> the question is how often this will happen.

Anything that adds more steps to the bridging process is bad.  One of 
the most powerful and valuable aspects of the PyObjC bridge is that it 
so totally transparent;  much more so than CamlBones (doesn't do 
subclassing), Java<->ObJC (changes the API) and AppleScript<->ObjC (not 
intended to be transparent at all).

The developer is going to be defining new ObjC methods quite often.  
The current PyObjC module can complete replace ObjC within a Cocoa 
project.  That is, Python is used to create all of the custom classes 
that one would normally find in a Cocoa project.   As such, the 
developer is writing lots of custom methods that implement the 
functionality specific to their application.   Certainly, there are 
many cases where the developer is simply overriding existing Cocoa 
providing functionality.

As it is, many of those methods have to be declared such that the 
bridge can figure out how to do the dispatch.   Very unfortunate, in 
and of itself, but livable.   It would be even more unfortunate if 
every single action method and other custom methods had to be declared, 
as well!

b.bum