Objective Modula-2 wrote:
Frank Heckenbach wrote:
protocols (like Java/Delphi interfaces) correspond to abstract classes with only abstact virtual methods, implementing interfaces corresponds to (multiple) inheritance
In his book "Programming Language Pragmatics", Michael L.Scott distinguishes between multiple inheritance of specification and multiple inheritance of implementation. Protocols provide multiple inheritance of specification but not multiple inheritance of implementation.
As I said I was trying to understand the differences coming from C++, i.e. seeing if and how Objective-C features can be mapped to C++ features.
Yes, in C++ inheritance applies to specification and implementation, but when there is no implementation, i.e. an abstract class with only abstact virtual methods, inheriting from it is effectively of specification only.
so the NSObject protocol would be the common ancestor, all classes implement (inherit from) it, and "id" would then be a pointer/reference to "NSObject_protocol".
The terminology for ancestor is superclass and root class (top level) and protocols are not classes, so they are not considered ancestors.
Terminology aside, I still think that protocols can be mapped to "pure abstract" C++ classes (of course, resolving a name conflict between a protocol and a class with the same name), and then the NSObject protocol would be implemented in (Objective-C) or inherited from by (C++) any other protocol and class.
The terminology for implementing a protocol is "conform to" and you can send a "conformsTo:" message to a class asking it whether it conforms to a given protocol. Protocols can also conform to other protocols.
"conformsTo:" would then correspond to an inheritance test (like "is" in Pascal, or trying a dynamic_cast in C++), in the special case that the right operand is a (C++ class that corresponds to an Objective-C) protcol.
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.
Some ideas:
- Keep the differences as small as possible (ideally: Objective-C class -> C++ class with an additional, auto-generated dispatch method).
- Use compiler switches, as GPC already does for the 4 supported object models.
- Actually support Objective-C syntax (if it doesn't cause too many syntax conflicts), whether or not one is trying to keep compatible objects.
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.
Except for package (though in BP, private actually means package (unit) wide visibility, not entirely private).
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.
IIUC, this works retroactively, i.e. if a module A calls a method of (sends a message to) an object declared in a module B, and module C extends that object via a category, even if neither A nor B know about C, it affects this call/message, right?
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.
Sure, but this seems like a rather minor problem to me. We already need name mangling (as does e.g. C++) to map overloaded operator names and other stuff to names representable on the assembler/linker level, so we could probably employ this or something similar here.
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.
As long as it's about generated output code, I don't care at all.
For the user to write it, it's not nice, of course. So we could:
- Actually support Objective-C syntax (see above)
- Make Send a method (at least syntactically) that returns a reference to the object, so calls wouldn't nest as much:
foobar.Send("setFoo:", 123) .Send("rotateLeft:", 456) .Send("splitAt:", 789) .Send("shuffle"); foobar.Send("setFoo:", foo.Send("count")) .Send("rotateLeft:", barbaz.Send(bam.Send("boo:", 123)));
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.
^[citation required]
We've had this claim in this thread before. I asked the question, which is still unanswered: How do you implement a generic list type with the following properties:
- Implemented only once in source code
- Applicable to any given type
- Statically type-safe (i.e., if you apply if to TApple, you can be sure at compile time that it contains only apples)
So far this question has been ignored. Until I see a valid response, I will ignore further claims that templates are not needed.
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];
The emphasis was on automatic. So can you, as a class designer:
- Enforce certain actions that are always done on instantiation (e.g. ensure that certain object fields are always initialized to certain values, which don't have to be constant, but might be a running index or something). I imagine this might be possible by implementing an instantiation method in the class that does this, but I'm not sure.
- Enforce certain actions that are always done on deletion of an object, whichever way this happens. E.g., if an object (not a pointer/reference) goes out of scope, its destructor is called; if a container (list, map, ...) is destroyed, for all of its contents their destructor is called, etc. A typical example is memory allocated internally -- you might point to garbage collection (which I don't consider a panacea), but to give another example, imagine that the object holds system resources (file locks, network connections) that you want to be released/closed when the object ceases to exist.
exceptions
Again, in Objective-C, exceptions are also just messages
Well, in C++ exceptions are just values (of any type).
But that doesn't answer the main features of exceptions:
[fooException raise];
Does this do what raising exceptions in other languages do, i.e. "jump" to the nearest enclosing appropriate catch-block? Or does it just send the message and continue with the next statement?
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.
It seems so. (Which also means, since I have no real interest in either of them, I should probably get out of this discussion and leave it to those who might actually implement it.)
Frank