Frank Heckenbach wrote:
As for Objective-C, I'm not very familiar with it. Do you have a list of features that would need to be added to support these libraries?
The minimum required would be: * declare a class * declare a protocol * add a method to a class * send a message
depending on implementation you may also need to expose * defining a selector * testing of selectors for equality
Note, that in ObjC certain operations that are basic operations elsewhere are just messages, for example instantiation of a class is a message. However, at the runtime API level, instantiation of a class is a separate API call.
In a language that already has its own object model and syntax to declare classes and methods, the first design decision to be made is whether or not to use the same syntax for declaring ObjC classes. If native syntax is to be reused then the next question is how to distinguish between native classes and ObjC classes.
One possible route would be to use a qualifier in the header of the compilation unit and use the exact same syntax within the compilation unit. For example ...
Unit FooLib; type FooClass = class ... end; (* native class *) end FooLib.
Unit BarLib Foreign "ObjC"; type BarClass = class ... end; (* ObjC class *) end BarLib.
Another possibility would be to add a qualifier to the declaration itself ...
type FooClass = class ... end; (* native class *) type BarClass = objc class ... end; (* ObjC class *)
Objective-C has four visibility modes for instance variables: public, package, protected and private. One of those can be made default, for the other three some kind of qualifier will be needed. Possibly such qualifiers already exist in the native syntax.
Although it may seem convenient to reuse native syntax, it may lead to inconveniences further down the road.
A very important feature in Objective-C is the ability to add a method to a class outside of the scope of the compilation unit where the class is declared. In Smalltalk and Objective-C this is called a category.
The consequence of this is that if your syntax embeds your method declarations inside your class declarations then you need yet another syntax for out-of-class method declarations in order to support this important feature of Objective-C.
When we designed the Objective Modula-2 extensions this was probably the most difficult thing. We tried several approaches and it always seemed like opening a can of worms.
We tried the class-is-a-record approach with methods declared inside a class ...
TYPE FooClass = CLASS ( NSObject ) a, b, c : INTEGER; (* instance variables *) PROCEDURE methodFoo ... PROCEDURE methodBar ... END; (* FooClass *)
... but this posed a problem when trying to support the category feature because there didn't seem to be any good way to declare a method outside of the class and link that method to a class declared elsewhere.
We then tried the class-is-a-module approach. This solved the problem how to support the category feature as categories became modules but now we had program modules, library definition modules, library implementation modules, class definition modules, class implementation modules, category definition modules and category implementation modules. And all of these had to have different rules as to what can be declared in them and what the import and export rules were. This wasn't really satisfactory.
At a time when we had almost given up looking for a better approach, we found the inspiration in Oberon and Oberon-2.
Oberon had replaced variant records with extensible record types. A record declaration can be based on another record type which it then extends.
TYPE FooClass = RECORD ( BaseClass ) ... END;
Oberon-2 added a feature called type bound procedures. This turns extensible record types into classes with out-of-class method declarations.
TYPE FooClass = RECORD ( BaseClass ) foo, bar : INTEGER; (* instance variables *) END; (* FooClass *)
PROCEDURE (self : FooClass) setFoo (foo : INTEGER); PROCEDURE (self : FooClass) setBar (bar : INTEGER);
Adopting both these concepts in Objective Modula-2 allowed us to get rid of all those extra module types and provide the ability to add methods to a class outside the compilation unit in which it is declared (aka category).
Now a category is simply a library module that imports a class from another library module and then declares one or more methods targeting that class.
DEFINITION MODULE FooCategory; FROM FooLib IMPORT FooClass; PROCEDURE (self : FooClass) multBar (by : INTEGER); END FooCategory.
(Note: we actually use CLASS and METHOD in Objective Modula-2)
Now, I am not saying that GPC should follow this approach, but this example illustrates that one design decision that looks convenient at first could lead to an inconvenience elsewhere. It is important to look at the features required to support Objective-C as a whole, not in isolation.
Another tricky Objective-C feature is the messaging. Again, at first it may seem convenient to simply map this to whatever the native function or procedure call syntax is, but this too can lead to unwanted and inconvenient consequences further down the road.
A simple method invocation in Objective-C looks like this:
[obj message: param];
which could be mapped to by Pascal syntax like this:
obj^.message(param);
However, method invocations in Objective-C can look like this:
[foobar setFoo: 123 andBar: 456];
the method's name is actually setFoo:andBar:, including the colons. The Pascal compiler would have to know how to reconstruct this name from whatever the Pascal name is. Since Pascal doesn't allow colons in identifiers this gets a little tricky.
The Python Objective-C bridge uses underscores to stand in for the colons ...
foobar.setFoo_andBar_(123, 456);
Luckily, the Objective-C style guidelines recommend camel case identifiers and underscores are almost never seen in Objective-C code. Still, the method names can get rather long and their readability suffers under the PyObjC scheme.
Moreover, it is very common in Objective-C to chain and to nest messages ...
[[[[foobar setFoo: 123] rotateLeft: 456] splitAt: 789] shuffle]; [foobar setFoo: [foo count]] rotateLeft: [barbaz [bam boo: 123]]];
in PyObjC style mappings these become
fooobar.setFoo_(123).rotateLeft_(456).splitAt_(789).shuffle; foobar.setFoo_(foo.count).rotateLeft_(barbaz(bam.boo_(123)));
in schemes that simply map [obj message] to Send(obj, message) such as cocoa-gnat does, this becomes extremely bad ...
Send(Send(Send(Send( foobar, "setFoo:", 123), "rotateLeft:", 456), "splitAt:", 789), "shuffle"); Send(Send(foobar, "setFoo:, Send(foo, "count"), "rotateLeft:", Send(barbaz, Send(bam, "boo:", 123))));
The many levels of square brackets in the Objective-C message passing syntax can be annoying, too, but the mappings to other notations usually become unreadable very quickly.
Many Objective-C developers like the original Smalltalk syntax better than the Objective-C syntax, where
[[foobar setFoo: 123] shuffle];
is
foobar setFoo: 123 shuffle;
in cases where the message chain may be ambiguous, parentheses are used in Smalltalk. The above example could also be written as
(foobar setFoo: 123) shuffle;
It might make more sense to build an interface that uses the Smalltalk syntax in some shape or form, either by way of an escape syntax, for example like Objective Modula-2 does:
(* backquote escapes to Smalltalk syntax *) `foobar setFoo: 123 shuffle;
or by using a variadic Send function that takes message strings:
Send("foobar setFoo:", 123, "shuffle");
there are probably other ways, but in my experience it is a good idea to seek inspiration in the original Smalltalk message passing syntax.
C++ this would be templates,
Objective-C doesn't have templates nor does it require them because you can choose between static and dynamic typing. Either way, you don't have to implement any template syntax translations.
automatic con-/destructors
In Objective-C constructors and destructors are just messages, so there is no need for special syntax and translations.
foo := [[FooClass alloc] initWithFoo: 123];
exceptions
Again, in Objective-C, exceptions are also just messages
[fooException raise];
Although there is special syntax for critical sections and try-catch-finally blocks. However, in Cocoa the exception system is based on a class NSException, so you should be able to simply plug into that.
After reading a bit about Objective-C, ISTM some of the major differences to C++ are:
The most important difference is that Objective-C is late bound. Everything happens at runtime. Classes are added at runtime. Protocols are added at runtime. Methods are added at runtime. It's all dynamic. You can send a message to a class that doesn't implement the message and the class can forward that message to a delegate. You can test at runtime if a class implements a message ("respondsTo:"). You can override the methods of the superclass, etc etc etc. All this happens at runtime.
So, AFAICS, it would be possible to implement the language features of Objective-C in a C++ output through a converter tool with moderate effort.
However, the original question seems to be more about binary compatibility to existing Objective-C code, which would probably not be achieved this way.
I don't think you would want to merely reimplement the ObjC runtime library and hook into it with your own syntax. Sure, this might be an interesting thing to do and it might actually turn out useful.
However, the primary reason for providing an Objective-C interface is usually to be able to use the Cocoa or GNUstep APIs. For that, you will need to interface with the Objective-C runtime library.
Whichever way you do that, the Objective-C runtime reference will probably be required reading:
http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ObjCRun...