Tepid Cocoa

3629

I’ve not had a chance to dive into Mac OS X GUI programming until a few days ago, where I first came into contact with both Objective-C and Cocoa, Apple’s application API. My impressions of both are rather mixed; I like some things, I heartily dislike others. Altogether, the whole experience leaves something to be desired, and is a far cry from the hot, sweet, chocolaty goodness one might expect from the delicious name.

Objective-C is a strict superset of C, which makes it incredibly easy to incorporate C libraries into your otherwise object-oriented code. It’s maybe a tad easier to do than it would be in C++ courtesy of the #import preprocessor command, which works the same as #include except it also provides a guard against importing the same header more than once. In practice, that feature is pretty pointless when it comes to including C headers, as any well-written header contains an include guard anyway. On the other hand, #import still makes life easier when dealing with Objective-C headers.

What mars the integration of C and Objective-C is that Objective-C’s syntax is so vastly different from C’s that it’s sometimes hard to decide which to use. Here’s an example:

1
2
3
4
5
printf("Hello, %s!", "world");   // C-style call
NSLog(@"Hello, %@!", @"world");  // Objective-C function call
// Compare to Objective-C "Message sending"
[some_object some_message : first_parameter_value
    second_parameter_name : secend_parameter_value];

Aside from demonstrating the rather nifty feature of serializing any NSObject * via the “%@” format flag, the above snippet also shows clearly how different Objective-C considers invoking a function, and “sending messages” to objects. I’ll admit that I don’t understand the reasoning behind terming something message sending that’s essentially nothing but a function call with an implied first parameter to an object.

Compare with C++…

1
2
3
4
5
6
7
8
9
10
11
struct foo
{
  void bar()
  {
    // in this scope the variable 'this' is a pointer to the
    // foo instance that bar() was invoked on.
  }
};
 
foo f;
f.bar(); // inside, this is equal to &f

… and Python:

1
2
3
4
5
6
7
8
class foo:
  def bar(self):
    # self plays the same role as this in C++, except that
    # you explicitly specify the name.
    pass
 
f = foo()
f.bar() # inside, self is equal to f

But whether it’s sending messages, invoking methods, or calling instance functions, it’s all just a matter of names, and I can live with odd nomenclature. What gets me is that for no reason that I can really understand, the syntax differs so vastly between functions and, err… messages?