Stop the Hate: Obj-C Deserves Your Love
intridea.com
intridea.com
Language research has progressed. Microsoft has invested heavily in C# and related technologies. Even Smalltalk research moved on -- strongtalk, newspeak. We have alternative, real-world usable languages running on the JVM, from Scala to Clojure.
Yet Objective-C moves forward one slow, stuttering step at a time. There are no namespaces. There are no self types (your init methods all have to return id so that they don't conflict with other init methods that have the same name). There are no private methods. Writing an initializer takes 3 lines of boilerplate, every time, plus the header declaration:
if ((self = [super init]) == nil)
return nil;
return self;
The language is obtuse, ridiculously verbose, frustrating to use, and downright paleolithic compared to modern deployed languages. It's a joke compared to everyone else's modern language research. I suffer through it full time because that's what the platform demands, but I would shoot it in the head in a second if I could.Nuke it from orbit. It's the only way to be sure.
Anyone who thinks ObjC is a good language either hasn't actually spent significant time outside of C/C++/ObjC, or is still new to the wide, wonderful world of Mac/iPhone development.
I'm guessing you've never written a Windows app with C++ and MFC. Or have done any hardcore UI development in C# or Java - both languages that are easily way more verbose - and require way more boilerplate - than Obj-C.
My assumption is that you simply don't grok it, that you haven't learned how to utilize dynamic dispatch, KVO, etc. to greatly simplify and streamline your application designs. Or you are one of those script kids that takes all the low level shit for granted. This isn't python. This isn't ruby. This isn't even smalltalk. It's a high level layer on top of a low level language. You don't get that kind of performance without some sacrifice, but rest assured that sacrifice is significantly less than C/C++ while maintaining similar or the same performance.
I have no doubt that method dispatch is significantly slower than vtables, but you're ignoring the fact that for performant code, plenty of C++ devs believe that vtables are far too slow as well. Large high-performance C-style projects are always struggling with the tension between the indirection that architects want to keep the system clean and the hardwired directness that the profiler says the system needs to be fast. ObjC didn't introduce this dilemma; function pointers did. It's so well known in C++ code that the MIT Click Modular Router even got distributed with a tool that automated de-virtualizing method calls.
In both C++ and ObjC, when dispatch gets scary, you write C code. The difference is that C++ pummels you about the head and shoulders for even considering writing straight C with naked pointers, while ObjC could care less.
I would rather avoid ObjC. I would rather build a large system out of any high-level language, from Scala to Ruby to Python to Lisp, and use an FFI to drop into C code. But I'd spend the rest of my career in ObjC without so much as a Bourne shell script to fall back on than I would willingly start another project in C++.
http://www.mikeash.com/pyblog/performance-comparisons-of-com...
Nice try, though.
This is why it's easy enough for advocates of python/php/ruby to say "just code the slow parts in c" but often far harder to actually do this without losing any advantage the higher level language bought you in the first place.
What language would you choose to write something like Protools, Photoshop, Maya, Visual Studio etc in? Definitely not C and definitely not Obj-C.
Again, I simply call bullshit on the idea that you couldn't write ProTools or Photoshop in ObjC. The portions of those systems where you care deeply about performance can be written most effectively in bare-metal C anyways; it's a delusion of C++ programmers that all the shellac and geritol that C++ offers is giving them a major performance benefit. It's C++ that forces you to make a lifestyle decision by pretending that pointers are anything other than register-sized integers. ObjC is just enough object goop layered over straight C to make large programs maintainable.
Again, I've seen first hand a big, native UI project crash and burn on Obj-C dispatch overhead that is now trucking happily along in C++. Have you?
You talk like adoption of C++ is a testimonial to C++'s power. The fact is, the market picked C++. Your realistic choices for bare metal app dev are straight C, which you can use anywhere, or C++, which you can use anywhere. If you want native objects, you're going to use C++.
There are two places where ObjC is even an option:
* On Apple stacks.
* In SaaS/ASP/service backend code.
In both of those places, ObjC is better than C++. If you care about portability, write in C or JVM+C.
Apple is now suggesting that you use three-character class name prefixes, since they claim all the two character ones. I had my two character prefix claimed by a new private framework Apple added to iOS, and now one of my class names conflict with one of theirs. Kaboom.
If you go the no-prefix route, your code isn't library-reusable since other people will do the same thing, and you will still get screwed -- Apple regularly claims non-prefixed classes in their code, too.
My assumption is that you simply don't grok it, that you haven't learned how to utilize dynamic dispatch, KVO, etc. to greatly simplify and streamline your application designs. Or you are one of those script kids that takes all the low level shit for granted. This isn't python. This isn't ruby. This isn't even smalltalk.
Seeing as you're writing ObjC using a compiler I've worked on, I think that probably understand the "low level shit" better than you do.
What?
If Apple developed a first-class alternative to ObjC I would switch in a heartbeat. In the meantime -- to write Mac/iPhone apps -- I will continue to use it.
So you saw that talk at WWDC as well? Every engineer from Apple that I've spoken to and asked about this has gone "What?! Did he really say that? Ignore it. We don't recommend that. Not at all."
Seeing as you're writing ObjC using a compiler I've worked on, I think that probably understand the "low level shit" better than you do.
You work on LLVM? Props to you, if so. Thats an awesome project. However, if you work on gcc, I haven't used that in over a year :-)
(I kid. Props to you, either way. I can't do what I do without what you do.)
Regardless of what they say, Apple is still claiming new two-character prefixes, including the one I've been using for years.
You work on LLVM? Props to you, if so. Thats an awesome project. However, if you work on gcc, I haven't used that in over a year :-)
I'm a big fan of LLVM, but no, I've done nothing with it. That said, if you're using clang for your production builds, you're a much braver soul than me.
There are still plenty of codegen issues, especially in the new iPhone/ARM support. There's a reason Apple is still using GCC.
Hardly brave; I only use it personal projects (which target 10.6/64-bit Mac) and debug builds. Release/Ad Hoc/Distribution builds for what I work on uses llvm-gcc. But, I'm not responsible for those builds.
As for UI programming in C#, give WPF and/or Silverlight a try. They both have their downsides, but in the end they offer a far more pleasant experience than Cocoa Touch. I haven't written an MFC app in about 1.5 decades or so.
if (self = [super init]) {
/* do the init */
}
return self;
Huge advantage of this is that you can implement object pools, singletons, etc. transparently.You just wrote exactly the same thing I did, but in a style that triggers GCC warnings regarding using assignment as a truth value.
Huge advantage of this is that you can implement object pools, singletons, etc. transparently.
You might consider looking into Newspeak constructors to see how it can be (much) better done, with much less code.
In short, treat constructors as class methods, allow them to be used interchangeably, support self-types so that you can't get selector conflicts, enforce calling of the constructor so you don't have to rely on documenting the designated initializer.
The long method names don't bother me.
Here are some reasons I think Objective-C needs to be retired:
- Header Files: These are archaic and require you to repeat code unnecessarily. Compiler's shouldn't require humans to do something that computers are better at.
- No Automatic Garbage Collection: In ObjC 2.0 we have this, but not on the iPhone. Unless you are making a high performance game, there is no reason the phone can't handle Automatic GC.
- No NSDictionary/NSArray literals: [[NSDictionary alloc] initWithObjectsAndKeys:@"value", @"key", @"value2", @"key2", nil]; // Enough said
- No regex: You kind of get regex's in 3.2+, but they are very limited and require around 3-4 lines of setup to get anything done.
- Xcode: You are pretty much required to use Xcode and I don't like Xcode. Even if you use the "xcodebuild" CLI, you still have to create the project through Xcode.
- Closures: I guess we will be able to use these soon, but it is going to take awhile for all the API's to get updated to accommodate them.
- No dynamic variables: It's handy to be able to shove data into objects sometimes. It's a hack, but as long as you treat it as such you can save a lot of needless code. (You can do this via the ObjC runtime, but it's messy)
- Unit Testing: It barely exists and is difficult to use.
- No namespacing: ObjC handles namespaces by prefixing class names. Blah, that is so 1978.
I just wish I could use it for iPhone development. :)
Seriously, how would you get a list of all functions in a module without an IDE? Besides, I put all my documentation into h-files as well, so other devs can pretty much see what I am doing without ever glancing at c-files.
With Ruby or Java you need some advanced folding support in your editor or a full-fledged IDE.
These "people" don't also seem to get when you distribute a lib, you need to distribute headers with them.
But good enough to write major parts of an operating system in by a company full of people easily smarter than you? Say what?
> Header Files
It's C for chrissakes.
> No GC on the iPhone
Because it's a performance penalty. Clock cycles on a phone are vastly more important than on a desktop/laptop. I can guarantee you this will change in a few years.
> No NSDictionary/NSArray literals
It's not a scripting language. Show me array literals in C or C++ that map to an underlying collection class that gives you fast enumeration and then we talk.
> Xcode
Personal preference.
> Closures
They're called Blocks.
> No dymanic variables
It's called 'id'.
id whatever = [[YourObject alloc] init];
But even better: id whatever = [[NSClassFromString(@"YourClass") alloc] init];
Or how about setting properties on objects dynamically? [yourinstance setValue:@"Hello" forKey:@"property"];
Or dynamically dispatching methods?Ever messed with vtables in C++?
> Unit Testing
Agree, but that's changing.
> No namespacing
You bitch about all the typing, but you want to type out namespaces instead of using a prefix on your classnames. Ok ...
Your confusing ObjC with Ruby, Python, et al. But it is not any of those. Like I mentioned elsewhere, it's a high level layer on a low level language. Adjust your expectations accordingly.
#define NSDICT(...) [NSDictionary dictionaryWithObjectsAndKeys: __VA_ARGS__, nil]
#define NSARRAY(...) [NSArray arrayWithObjects: __VA_ARGS__, nil]* The language is verbose.
* Practically speaking, it's only used to developer for two platforms (OSX and iOS).
* The frameworks for those platforms are MEGA verbose.
* The memory management model for the iOS platform is not GC, and it's not manual management. Frankly I found manual management of memory simpler than retain/release. And the autorelease pool? That's just wrong.
* Typically speaking back to two files per class.
* Doesn't have any functional elements to it whatsoever. Any manipulation of collections = instant development velocity kill.
* Typically have to deal with two different kind of strings (NS versus C).
So for now, yep, I still hate ObjectiveC.
The memory management model for the iOS platform is not GC, and it's not manual management. Frankly I found manual management of memory simpler than retain/release. And the autorelease pool? That's just wrong.
retain/release + autorelease pools solve the ownership problem inherent in manual memory management system. You can return a heap allocated object from your function/method and neither you nor the caller have to be concerned about how it will be cleaned up.
Not sure what's wrong with that solution -- I've even implemented/used an equivalent implementation for pure C code.
NSString has plenty of methods to deal with this, and you get boxing for free between CFString and NSString.
> The frameworks for those platforms are MEGA verbose.
Which some view as self documenting.
And that pesky char * that you get from C.
There are methods like makeObjectsPerformSelector: and now methods for taking blocks.
Sending a selector is not functional, true, because it is an OO language, not a functional one. So the idea is "send this message to all these objects" instead of "call this function on all these objects."
Unfortunately, I don't see anyway to create a new collection from an existing one by sending each object a message (the equivalent of map). Furthermore, some methods actually do take C functions, and others take an NSPredicate. It would be more consistent if they had found a way to do all these things by sending selectors and a varargs list.
(It seems like blocks is the new, improved way to do all these things, and rather functional, but all the older ways still exist, so a developer must understand all of them.)
Using a language like obj-c where you have to do memory management manually just seems so archaic after using modern languages. Plus there is strange property duplication syntax, split header/code files, a GUI editor that doesn't easily wire events to code, named parameters, c/smalltalk calls mixed together, etc.. it's just a mess.
In my brief stint using it the whole time I kept thinking this would be so much simpler if I could do it the XYZ language way. Obj-C is a language that you have to try really hard to like. If you have to convince yourself then maybe it's not that good.
The "property duplication syntax" (I assume you mean the declare versus synthesis) is there for flexibility and so you can do some pretty good customization to make your classes work better.
For OS X, Objective-C now has garbage collection that works pretty well.
That's not an Objective C thing, the language has garbage collection, just it isn't enabled for the mobile platform, for the reason it eats power and memory.
`[object performSelector:sel];` // where `sel` may be - retain
How should the compiler optimize that?Plus there is strange property duplication syntax
You don't have to bother with that anymore. The only reason you ever did with iPhone dev is because the iPhone Simulator didn't support the modern runtime. If you only tested on the device, you never had to bother with it.
As of LLVM 1.5 (in Xcode 3.2.3) or 2.0 (in 4.0) on 10.6, the compiler can fake enough for runtime support (and only requires @property declarations - no more ivar or @synthesizers): http://www.mcubedsw.com/blog/index.php/site/comments/new_obj...
named parameters
Objective-C doesn't have named parameters. It intertwines the method names with the arguments that it takes.
Instead of `void doStuff(foo, bar, baz);`, its `- (void) doStuffFoo:(id) foo bar:(id) bar baz:(id) baz;` (which can also be written (and compiled) as: `- (void) :foo:bar:baz;` if you wanted).
"Our mobile development team is highly specialized in creating applications for many popular mobile platforms including the iPhone..."
Does "highly specialized" mean learned it last night...
Erm, not true. For example, NSString's
+ (id)stringWithFormat:(NSString *)format, ... + (NSString) stringWithFormat: (NSString *) format, ... {
NSString *string;
va_list ap;
/* Fetch the arguments */
va_start(ap, format);
// Could iterate over the arguments yourself here, or just use:
CFStringRef cfString = CFStringCreateWithFormatAndArguments(NULL, NULL, (CFStringRef)format, args);
string = [NSMakeCollectable(cfString) autorelease];
va_end(ap);
return string;
}I would recommend use of Objective-C without Apple frameworks to anyone who must build robust modular systems while retaining C compatibility or performance characteristics. I use it myself in a game engine.
However, I fail to see why I should have to worry about it and do it manually.
Assembler was probably part of many peoples basic training as well. Do you want to spend your days juggling everything in 4 general purpose registers because it makes you feel like a better programmer? Is that the best use of your time?
GET OFF MY LAWN YOU DAMN KIDS WITH YOUR FANCY PYTHON.
It really is sad that so little of the state of the art in GC is available in mainstream languages.
You could contrast it with malloc/free in the unix/C ecosystem. Get a pointer back from function X in library Y. What do you do when you are done? free? call X_Z? constraints on the order of freeing dependent objects? That is a trip to the man pages every time.
In that context, Objective C is the closest you will find to a best of both worlds language for responsive user interfaces. Being a strict superset of C, you can control the performance characteristics of your application to your hearts content. With SmallTalk style message passing, you can implement highly dynamic object oriented designs.
The warts that come along with this are the places where C still pokes through when you just want to work in a high level object oriented context and things like header files and static variables rear their ugly heads.
I'm really starting to doubt the intelligence of HN.
So again, how can you be sure that the reference you just released isn't the last live pointer to some huge datastructure that now has to be torn down reference-by-reference?
If you release an object and it gets torn down, it means you didn't increment the ref in the right place. And I don't get how release/retain is such a difficult concept to grasp. If you don't think you can deal with it, should this be your profession?
If you release the last pointer to a complex datastructure that has no other references, you certainly should hope it gets "torn down" = deallocated. If that object happened to contain a lot of other objects they will each in turn have to be released. Obviously your main code execution path is going to halt while this graph is walked and released.
Maybe Jimbokun is right that you can control this better in a ref counting scheme than in a typical GC but you're hardly immune from the problem.
With a garbage collector, there are more things that are out of the developer's control, like when exactly the garbage collector will run and for how long.
C languages don't magically always perform better than other languages, but they do give you a greater level of control over what happens when. Whether that's a good or a bad thing is up to you.
NSObject Class Reference
– performSelector:
– performSelector:withObject:
– performSelector:withObject:withObject:
why stop there, lets tack on more withObject arguments
Syntax and naming conventions are another matter...
Ruby --> Obj-C or PHP --> Obj-C
Just for references sake. Or some "gotchas".