First Glance at Objective-C and the iPhone SDK (by a Java and C Developer)
webbtech.posterous.com
webbtech.posterous.com
"When I first realized the language offered weak typing -- with the (id) variable -- it seemed to go against everything that C stood for in my mind."
These are good observations, and reflect deliberate choices in the design of Objective C.
The funky message syntax makes clear that a sending a message is not equivalent to calling a function. Conflating the two will eventually lead to pain and confusion.
Declaring a variable as "id" does indeed launch you out of C's type system, into a realm where any object can potentially respond to any message, regardless of its type. This leads to a lot of interesting possibilities and patterns that Cocoa (and iOS) leverage heavily.
It's also very much like calling a virtual function in C++, only slower.
1) Load class pointer from object movq (%rdi),%r11
2) Load cache pointer from class movq 0x10(%r11),%r8
3) Load cache entry (IMP) from cache movq 0x10(%r8,%rcx),%r11
4) Load function pointer from IMP movq 0x10(%r11),%r11
Notice that each of these loads reads into a register which is then treated as an address by the next load. This does a great job of totally stalling your pipeline while you wait for memory reads. I've been staring at this same grim pattern in the profiler since the days of PowerPC.
C++ virtual function calls are doubly-indirect in the worst case (read vtable pointer from object, read function pointer from vtable). And because it's emitted at the call site and not hidden in a function, the compiler can often reduce it down to singly indirect or even direct link it as a static call, if it can prove the exact type.
Objective-C is not as bad as some say, but if your code is highly optimized, method call overhead can become a bottleneck.
In my experience, Cocoa Touch has all the benefits of it's very mature Mac OS foundation, and to develop effectively, and minimise friction, you need adhere to the Cocoa way.
I'm sure we'll see gc on iOS devices eventually, but it's probably too memory hungry to be practical on the phone right now.
- The ability to assign types as ClassName<Protocol>, instead of the protocol specifying the type completely. Neat, I guess...
- Because it's message passing, you get duck typing for free, albeit with compiler warnings (you send a message, and wouldn't you know it, the selector exists!). Not that I recommend this approach over protocols.
- The awesomeness of @selector, especially if you're coming from Java and used to writing anonymous classes everywhere simply for the sake of making functions first-class entities.
- The lack of public/protected/private visibility modifiers and how variables are suddenly part of the public API when you define them in properties. Say you have a variable you want to keep private, but you need to frequently update its value. You go ahead and define @property (nonatomic, retain) for it so within the class so that you can simply do self.varName = newVarValue to update it. But now all your clients/outside clients will see; you need to write the release-and-retain setter yourself in the .m file to prevent this.
- The minimalism of Xcode. Hey, it's faster than Eclipse, thank $DEITY for that. But when I want to alphabetize the filenames in the left sidebar, I have to go to Edit -> Sort -> By Name for _every_ file group?
@interface MyClass (PrivateMethods)
@property(readwrite, retain) NSObject *myProperty;
@end
@implementation MyClass ...
Now only your implementation knows about the generated setter methods, and you don't have to implement them yourself.
@interface SomeClass (SomePrivateCategory)
@property (nonatomic, assign) NSUInteger count;
...
@endSecondly, while this is minor, I find it annoying that when declaring array's I have to include nil at the end.