8 August 2009
In a thoughtful post at the Big Nerd Ranch blog, Joe Conway talks about the relatively new dot notation in Objective-C for invoking messages on objects.
The executive summary is, he doesn’t like it.
He’s making two arguments against dot notation:
- While it is now legal Objective-C, it’s an uneasy fit to an enormous history of Objective-C code, and existing coding patterns in the language.
- It blurs the lines between accessing fields in a structure and invoking code, and that’s bad in and of itself.
I have no argument at all with point 1. I personally dislike the brackets notation, but that’s just years of writing C++. Objective-C is a different language, different syntax, get over it, write some code: no problem.
Point 2… well. Maybe this is also my years of C++, but I really don’t see the problem. For example, he writes:
In Objective-C, the square brackets () were added for message sending. While the square brackets had previously only been used for indexing an array, the intent of the brackets can be easily determined by the context.
That’s true, but the original reason that Objective-C used brackets was not to differentiate message sending from structure access; it was because Objective-C was (and largely still is) a preprocessor on C, and using brackets in that way made it easy to parse and do the substitutions. I’m entirely in favor of making a virtue of that necessity, but let’s not forget that the original reason was arbitrary, and unique in the history of object-oriented extensions to C.
He goes on to say, in the example:
int x = foo.value;
What does that mean? Are we getting the value field out of the structure object foo? Are we executing a simple method that returns a value? Or, in this case, are we creating a network connection, pulling a value from a web server, turning that data in to an integer and then returning it?
Well, yes, but we really don’t any more in:
int x = [foo value];
except that we’re running some code. He writes:
Our first glance tells us we are definitely sending a message. That clues us in that more work is being done, not just a simple memory offset and an assignment.
OK, good, we do know that we’re sending a message, but… well, we still don’t know anything at all about the nature of the message than we did in the first example. Calling these things “foo” and “value” is stacking the deck a bit, too; if the example was either:
int remoteMemoryTotal = remoteConnectionPartner.getRemoteMemoryUse;
int remoteMemoryTotal = [remoteConnectionPartner getRemoteMemoryUse];
it’s a bit harder to argue that we have zero information about what’s going on.
My preference for dot notation largely comes from the desire for encapsulation. I like the idea that if I need to swap out an implementation detail, I can do so without a syntax change. For me, the fact that accessing a field off of an object, and invoking a method on that object use the same syntax is a feature, not a bug.
Part of it is cultural, I suspect. Objective-C is an interesting hybrid language. The object model is very dynamic and fluid, very Smalltalk-y, but that’s added on top of C. Not a “C-like language,” but C. K&R C. Thus, there’s a huge difference (in philosophy as well as performance) between reading an int out of a structure and sending a message to an object that returns an int, and the syntax reflects that. In other languages, like C++ and Java, the philosophical difference is reduced (somewhat in C++, greatly in Java), and a founding principle of those languages was to make “get something from an object” be the fundamental operation.
He does make some good points about returning l-values from functions (something that C++ wrestled with unhappily), which is a requirement for writing really nice setters as well as gettings using dot notation. All in all, I agree with his fundamental point that:
You aren’t at home. You’re working with another language.
… even if I don’t accept the premise that using dot notation to invoke methods is fundamentally a bad idea.