Subscribe to
Posts
Comments
NSLog(); Header Image

Objective-C

Let's get into it quickly:

Do you really believe:
[[[MyClass alloc] init:[foo bar]] autorelease]

is easier to read or write than:
MyClass.alloc().init(foo.bar() ).autorelease()

Yes, I do. Some others from the list on which I have comments follow.

Love 5: Categories
Indeed, categories are a godsend. If I don't comment, I agree, but I've used categories so often in my own development that they deserve a hearty "hurrah" and this is it.

Love 7: Key-Value Coding
This is mentioned in the "Love" section, but "Hard to Write Good Getters/Setters" is listed in the "Hate" section. The two, to me, are pretty hand-in-hand. I love key-value coding. However, I avoid situations in which anything access my instance variables. I provide getters and setters for any public instance variables. Thus, the fact that they're a pain in the butt to write doesn't help. 🙂

Love 8: #import
Another hearty hurrah. Even in simple projects, the necessity to have a bunch #ifndef __EJB__FOO__ became tedious. #import is a godsend, and one I'm surprised has not been picked up by other languages.

Hate 1: Method-call Syntax
Yes, it would be lovely to be able to rearrange some of the parameters (they're named, so why not?). Yes, it would be lovely to have per-parameter default arguments. But the brackets? C'mon. Can't you find something else about which to complain? The brackets took me all of two minutes to learn, and as I said in the opening, I do find it easier to read. But hey, my earliest "code" was HTML, and I got pretty good at nesting tables. Maybe that has something to do with it…

Hate 10: Messaging nil
Agreed - something that should be eradicated, or at least exposed so that any messages I send to nil are flagged. REALbasic users are very familiar with "an exception of nilObject is found" (or however it goes), and we shouldn't ever go that far… just a little more help when debugging, perhaps.

Hate 11: Class unloading
Seconded. Thirded. Fourthed. Suppose I need to bundle a class used by 10% of my users. Loading a class takes 1 second, but the operation the class performs takes 25 seconds. Why should I force 90% of my users to delay launch time by an additional one second for absolutely no gain, not to mention the memory overhead? Ridiculous - and I hope something is done about this soon.

Hate 13: No Namespaces
Frankly, I'm rather indifferent about this one. Yeah, it might be nice, but I've really never seen too many collisions (just intentional ones, in fact). A lot of our products use "FSS" as a precursor to our files. No problem.

Hate 15: NeXTie Arrogance
Yawwwwwwwwn.

I'm going to add one point of discussion in answer to one question: why hasn't the language been improved lately? I'm going to answer that question with another: who's in control of the language? Who's the ruling body? What hurdles need to be cleared before a change can be accepted?

23 Responses to "Objective-C"

  1. Your opening: When presenting this, I got a smattering of folks who also thought the ObjC code was easier to read. However, they were all old-hand ObjC coders. Right now, I'm leaning towards ObjC bends your brain in the right way to easily read the brackets, but only after getting used to it.

    Love 5: Heh, I agree. Sorry about that, I was introduced to KVC in WebObjects/Java, whose getters/setters aren't hard to get right.

    In terms of your assertion the language has not been improved lately: that was an assertion of mine when I first started shopping this around, but found out this isn't the case. ObjC advancement was largely blocked on C++ grammar integration for an unexpectedly long time. But now ObjC++ is alive an kicking, and was worth it IMHO.

    Also, some new features have been added to ObjC in Panther.

    Finally, Apple is in sole control of the language, and is the ruling body. The hurdles seems largely what patches the gcc mainline is willing to accept. There's a reason Apple hired a bunch of gcc committers...

  2. Oops, that note about KVC refers to Love 7, not Love 5.

  3. I find the message call syntax (that is, the brackets) incredibly easy to read, and I've used some pretty terrifyingly deeply nested message calls in some of my code. But it's not that surprising that I don't have a problem with that, because I feel most comfy in functional situations and Lisp-like languages.

    A lot of things in Cocoa behave reasonably functionally, as in:

    [[NSString stringWithFormat:...] stringByExpandingTildeInPath]

    It's pretty easy for me to think of that in the same way I'd think of the equivalent in Lisp pseudocode:

    (expand-tilde (format ...))

    So I don't have a problem with deeply-nested messages.

    On the others: I don't use categories anywhere near as much as I should, although I have some excuses on certain projects. I love #import, and couldn't live without it.

  4. Objective-C does not have named parameters. The method name is the method selector; the two are synonymous.

    The method "setObject:forKey:" is named "setObject:forKey:" -- not "setObject: that takes an argument called "forKey:". Parameters are not optional and cannot be "reordered" (all features typically implied by named parameters).

  5. Okay Bill, but you're nitpicking. You know what we mean, man! 🙂

  6. Nit picking? Yeah, a bit. This is all a button to me... and it was pushed rather hard.

    It comes from having had this conversation over and over again for more than a decade. I have worked on many bridges between ObjC and other languages-- the notion that ObjC supports named parameters is a huge source of confusion.

    ObjC is really bloody simple (so is PyObjC, that was the point) and it is useful to the newbie to think of it in that simplistic light.

    Methods have names and they take arguments. The syntax is just sugar that provided a catalyst for the creation of a wonderfully powerful API (Foundation/AppKit -- once you "zen" with it) that is much more "self documenting" than the average, often terse, "functional" API.

    Let me rephrase: The syntax of Obj-C and SmallTalk is such that the API-- the method names, in particular-- naturally expresses details about the paramaterization.

    The syntax of Java, Python, C, and C++ style APIs do not lead to this natural expression.

    Consider a very basic operation like shoving a key/value pair into a dictionary.

    In ObjC, you have...

    [dict setObject: anObject forKey: aKey];

    ... and it natually indicates exactly what you are doing and how it should be invoked. Even rewritten into a functional form...

    objc_msgSend(dict, @selector(setObject:forKey:), anObject, aKey)

    ... or, in PyObjC (not using Python's dict notation)....

    dict.setObject_forKey_(anObject, aKey)

    ... the method name-- the API-- naturally exposes what it is going to do and how it should be called.

    Compare to Java...

    dict.put(aKey, anObject)

    ... (and most other languages). "put()" doesn't tell you jack about how the API should be used. If you were to glean the method signature at runtime, you get something like 'void put(Object, Object)'.

    Obviously, sticking something in a dict is fairly contrived. But consider the same with methods that take more arguments....

    ObjC's "goofy" syntax (ObjC has been around as long as C++ and SmallTalk around much longer than that -- so calling it "newfangled silliness", as some have, is to deny history) conveys a level of meaning that is of extreme value to the developer.

    If developers had a habit of declaring functional APIs with the same level of expressiveness, that would make development a lot easier.

    But developers are lazy and hubris demands terseness to maximize wizardly status. That ObjC offers an effective catalyst for developers to build APIs that are actually meaningful is a wonderful asset.

  7. I agree with some of the comments on the initialization stuff, as well as the setters/getters. But I'm puzzled by many of the other comments. They come across as indications that the author hasn't dug deep enough to understand why things are they way they are.

    The brace example is unrealistic. In most cases you're going to have a single method - [MyClass instance], or [MyClass instanceWithArgument:argument]. That's going to give you an autoreleased object.

    The memory management stuff just seems completely misunderstood. Apple could have everything do automatic memory management. Who wants to think about memory? The problem is you pay for it in efficiency. You may not notice on a servlet, and maybe not even a simple text editor, but you definitely notice on a complex desktop app. Last time I checked, users are pretty particular about how fast the app "feels."

    He says "Pity the newbies coming from scripting languages." My reaction is "no shit." Cocoa isn't a scripting language. It would be nice if you could get all the performance benefits without having to think about the computer as much, but it's just not that simple. You have to pay for the abstraction somewhere. So until computers get to the point where the performance difference is irrelevant, here we are.

    I've found great value in being able to send any message to nil, particularly in terms of rapid development. Not connecting outlets, well, that's a different type of problem. And IB does let you know about it by popping up that little exclamation badge on the object. Changing nil's behavior is overkill for the problem.

    I'm completely lost on the complaint about not being able to add instance variables using categories. That's sort of the whole point of categories. Does he know you can subclass?

    Namespaces -- sure. Why not. The complaint about the lack of an asterisk for the id. Well, whatever.

    I've seen PyObjC. It's an interesting idea, but it seems to get really messy really quickly. I'm sorry, but I just don't see Objective-C 'dying'. In fact, it seems to be taking over in terms of Mac desktop development.

    - Scott

  8. bbum: Sorry to push your big button 🙂 Point taken.

    Scott:

    Brace syntax example: I chose this example exactly because it's so common. Yes, you can wrap the ugliness inside a [MyClass classWithArguments:] class method so every client doesn't have to face it. That's exactly what I do. However, the ugliness is still there, and it requires more work for each class you write.

    Memory management: I believe automatic memory management is realistic today for complex desktop applications. Ada, Dylan and O'Caml are examples of fast, natively-compiled languages with automatic memory management. Give it another ten years, and C++ might be there as well.

    Messaging nil: I'm the type who adds assertions to his code everywhere. I also do this in the name of "rapid development". Maybe I'm shouldn't, since it's more "rapid error detection".

    Categories: I view categories as a method of building classes piecemeal (along the lines of C# 2.0's partial types). I define classes as "variables and methods". Thus, if I can't add instance variables to go along with my methods, that's only a partial solution to me. Yes, I know about subclassing -- I use it for different reasons than I use categories.

    Asterisk for the id: I did say it was more of a distaste than a hate...

    Objective-C 'dying': While ObjC's ranks are definitely swelling, I submit this is due to Cocoa, despite ObjC. Maybe it's the company I keep, but most of my professional desktop developer friends love Cocoa, but do not love ObjC. I think PyObjC is a credible threat to ObjC for the slight majority of Cocoa desktop applications.

  9. The comment about how method names naturally expose the usage of the API was a huge boon to me. I'm a relative newcomer to programming, started with C and moved on to ObjC, but I noticed quickly that I rarely needed to consult documents when figuring out what a method does, and what it accepts. Reading other people's code became much easier, because of the almost 'natural language' way in which the methods read. Of course, this is due largely to Cocoa using good method names, but ObjC makes it so that anyone can use such descriptive names for methods and parameters.

    Key/Value coding made a lot of sense to me. In fact, I almost didn't get it at first, because it was simpler than I thought it could possibly be.

    I like the brace syntax. Now, maybe you can blame it on the fact that I haven't been using other syntaxes as much as the braces, and I learned the braces fairly early in my programming life (only a few months after learning C). However, the idea of nesting just makes sense to me. It is less linear, and easy for me to follow. Now, you might say that the only reason I say this is because I learned it first, but you can say that about ANY syntax. What you learn early on begins to pattern your expectations and thought processes. I haven't gotten any indication that the brace syntax is a detriment to the language in any way. With proper indenting, it makes things look quite clean in my opinion.

    As to everything else, I haven't gotten deep enough into the language to really form an opinion yet... But I appreciate the comments, it gives me some ideas as to what to look for and what to leverage.

  10. I chose this example exactly because it's so common.

    I guess my point is that you can break it up, and that -init doesn't take an argument.

    I believe automatic memory management is realistic todayfor complex desktop applications.

    Not that I think you're being untruthful, but I'll believe it when I see it. I've been working on a Objc framework that is very sensitive to performance tweaks, and few things seem to affect the speed more than autoreleased vs. manual release. My other points of reference are Java and scripting languages, and neither are known for raw GUI speed.

    Bottom line -- you may be right, but I'm going to have to see a complex Cocoa app written in a language with auto memory management before I believe it's practical in terms of performance. I know we'll get there some day, I'm just not sure it's today.

    Messaging nil: I'm the type who adds assertions to his code everywhere.

    I think you're missing my point. During design/experimentation, I like being able to send messages to a placeholder (nil) that won't cause a crash. I can put a real object there later. Maybe it's personal taste.

    Thus, if I can't add instance variables to go along with my methods, that's only a partial solution to me. Yes, I know about subclassing -- I use it for different reasons than I use categories.

    The point of leaving variables out is to keep things simple. Things can get out of control very quickly if you have to go hunt down all your data declarations. The idea is to keep the classes "shallow." It may be that this convention doesn't meld well with your style, and therefore just isn't appealing.

    Objective-C 'dying': While ObjC's ranks are definitely swelling, I submit this is due to Cocoa, despite ObjC. Maybe it's the company I keep, but most of my professional desktop developer friends love Cocoa, but do not love ObjC.

    This may be an issue of circle of friends. My experience is that people like Objective-C (particularly over something like Java, for example) primarily due to the method naming syntax, and some also enjoy seamless integration with the mountains of existing C libraries. But I really think you underestimate the value of the ability to spit up the method name. If it wasn't for that, then perhaps the language wouldn't be anything special.

    I'm definitely not an ex-NeXT user. 🙂

    - Scott

  11. I've been working on a Objc framework that is very sensitive to performance tweaks, and few things seem to affect the speed more than autoreleased vs. manual release.

    That implies only that autoreleasing is slow compared to manual releasing. A good GC should have less overhead than fully manual reference counting.

  12. A good GC should have less overhead than fully manual reference counting.

    Hey, I have no attachment to managing memory manually. I would welcome automation. I just haven't seen an implementation that works well for complex desktop applications yet. Like I said, I want automatic memory management.

    - Scott

  13. I like Obj-C. PyObjC seems silly.

  14. Troll.

  15. Sorry. That wasn't fair.

    Why is it silly?

  16. A Balanced and Fair Look at Objective-C

    Jonathan Rentzsch has written a great article about what he loves and hates about Objective-C. I’ve wanted to write this article for a long time, but now Rentzsch has saved me the time and also done a better job than I probably would have. Now I...

  17. I think one's acceptance of the braces can be easier if you're coming from Pascal or C and Objective-C is your first OO language.

    In that context, it's not strange to find that method calls have a different syntax than function calls. They're different things, after all, especially in a language like Objective C with dynamic binding.

    When you're learning OO, I also think it's probably useful that the different syntax keeps the concepts of method and function separate. That way you can know "here I'm using a C function, not OO" and "here I'm using a method".

    But if you're coming to Objective-C from a language which uses parens for both functions and methods, then it probably does look strange.

    But yeah, I'm an old NeXT user. For what it's worth, Smalltalk has always looked weird to me. But Objective-C was my first OO language, and one of my first languages of any kind.

    - Jon

    PS: regarding the expressiveness (or not) of message calls, consider the case where a Java constructor invokes another constructor, and all you see is

    this(foo, bar, baz) or

    this(foo, baz), or

    this(foo, bar).

    and you lose what little information might have been provided in the method name.

  18. It's silly because I don't know Python, (I know PHP though), and I've never once wished for changes to OBJ-C, just changes to the framework. I guess that's not a very good answer, but that's all I've got.

  19. Some points on Jon Rentzsch's original message:

    Hate 6:

    You don't have to overwrite self in init.

    It is perfectly fine and actually preferred to write init more like the following:

    - (YourObject *)init;

    {

    YourSuperObject *superobject;

    superobject = [super init];

    if (superobject != nil) {

    }

    return (YourObject *)superobject;

    }

    Somewhere along the line people figured out that the compiler and practice of overwriting the self pointer didn't matter. Thus in the effort to save themselves from creating another variable they started writing the code as you showed. In reality, I write my init methods as a slightly shorter version of the above, mostly to save me typing:

    - (YourObject *)init;

    {

    id rc = [super init];

    if (rc != nil) {

    }

    return self;

    }

    Of-course this all gets back to writing more code than we really should have to. I also assume that the compiler optimizes my init to be fundamentally similar to your init.

    Hate 11:

    You can actually write your own class unloader. It isn't too hard to do this. The problems start when you want to reload the classes you previously unloaded. You have to save all of the information yourself and reconstitute it into the class hierarchy, since the classes were never really unloaded from memory just dereferenced. (There are other issues which I am not bothering to address, obviously, but I have written a class unloader and reloader and know it can be done.) Thankfully there is enough documentation of the runtime system for someone to do this if they are adventurous.

    Hate 15:

    Since I have been a NeXTstep developer since 0.8 beta, you bet I like the syntax. As you basically say in a roundabout way, there is nothing wrong with the syntax other than it isn't similar to the C++ style messaging syntax. Of course there would be problems if Apple tried to rewrite the syntax to look something like foo.bar(key:value, key2:value2, key3: value3) since it would interfere directly with the parsing of arguments of C and C++. [Yes, I know that the current Objective-C arguments are not named.] I prefer square brackets primarily because it helps make the Objective-C code jump out from the standard C and C++ code which I have to interact with.

    You missed a really big hate about Objective-C: no class variables! I do know the workarounds, but would like to see Objective-C get real class variables.

    I agree with the other posters that messaging nil is sometimes a good thing. I don't like having to track down that one instance of a nil object which isn't supposed to be nil either though. However, I can't think of a good way to allow me to have my cake and eat it as well so I will cope with having to finding those unwanted nil objects.

    Finally, WebObjects, in Java _sucks_ compared to the Objective-C version. I could easily write the 15 things I hate about Java coming from the Objective-C world. (I could probably come up with 10 that I like as well, but the hate side wins regardless.) G*d-d*mn helper-class hell. Why Gosling thinks he invented an object-orientated language, when you *have to* write objects which are totally meaningless in-and-of-themselves, I will never know. Java definitely makes me write more code that I shouldn't have to than Objective-C does.

    Mike Barthelemy

  20. ...coming to this thread really, really late... 🙂

    I have to agree with several comments above - where you come from determines how you feel about Objective-C.

    I'm new to Macintosh development but I've been writing Windows software using C & C++ for over ten years. I must admit I chose to work with Carbon over Cocoa largely becuase of hate #1 (and also because I'd like to share classs with a GTK application). Perhaps it's just an old dog refusing to learn new tricks, but the syntax seems convoluted to me. Methods are, ultimately, just functions with hiden member data passed to them so I fail to understand why they should have a different syntax.

    I understand the NeXT legacy and I appreciate language diversity, but Apple is doing themselves a disservice by ignoring millions of C++ developers.

  21. If you think that a method is a function with some data added, you're really too stuck in your C++ mindset and haven't grasped the most basic OOP concept.

    In ObjC, you can catch method calls that cannot be handled and do something else with it, that's totally unthinkable in C++. Additionally, since Mac OS X 10.1, you can mix ObjC and C++ in a single source file using ObjC++.

  22. Hate 6:

    I find this init to be both easy and sane:

    -(id)init;

    {

    if(![super init])

    return nil;

    myInitialization...

    return self;

    }

    (Okay, very late to the discussion, it seems :-P)

  23. Coming even later to the party... Joachim, I'm learning Objective-C myself, but I believe your example is incorrect. The problem is that [super init] may return a value different from self due to delegation for example. Personally I have no problem writing:

    -(id) init
    {
    if (nil != (self = [super init]))
    {
    // My init stuff
    }
    return self;
    }

    I've gotten into the habit of comparing nil (or NULL) to things with nil (or NULL) on the left side and not the right. It helps guarantee you don't accidentally do an assignment to nil (or NULL).