5 ms·
Objective-C is hands down one of my favorite programming language: - It's compiled, not interpreted. Even Java and C# are compiled into bytecode for a massive
by SeoxyS 14y ago
Objective-C is hands down one of my favorite programming language:
- It's compiled, not interpreted. Even Java and C# are compiled into bytecode for a massive VM to interpret. Objective-C has no VM, it's pure binary + a shared library to implement the runtime. It also uses the very best compiler, clang, which gives incredibly helpful error messages, warnings and suggestions.
- It's a strict superset of C. Even C++ does not meet this criteria. This means any valid C is valid Obj-C and behaves exactly the same way, in any Obj-C file. You can drop down levels of abstraction for performance, and can even write assembly if that's what it takes.
- It has an amazing and fully supported debugger in the form of LLDB.
- It's fully dynamic, allows introspection, duck typing and even monkey patching (with a little effort; method swizzling). Everything is an object, except for native C types.
- It takes the right approach to memory management. Realizes that garbage collectors are abominations, and that managing memory is really the job of either the developer or the compiler.
- It has the most fantastic concurrency framework I've ever used, in the form of `libdispatch`. Now, to be fair, it's a C library that ought to work anywhere, but practically it only works well on Apple's platforms and using clang.
- Apple is moving in the right direction, cleaning up the language, removing annoyances and making syntax more succinct.
- Header files. I think I'm on my own in liking this—but I think headers are amazing. They're a succinct and standalone version of a documentation file that is extremely useful to both developers and the compiler. Use them to describe well the public interface to your class, and you don't even really have to write documentation anymore.
- Solid design patterns and convention-driven. These are getting better by the day, with the recent addition of closures to the language.
There's two major annoyances:
- It's often needlessly verbose. Not in the syntax, mind you, which is just fine, but in the naming conventions. For example, `NSArray` has a method called `enumerateObjectsUsingBlock:` instead of simply `each:`. Add that up to every single name, and you get pretty ugly code—and good luck writing it with anything other than Xcode's context-aware autocompletion.
- It's tied to Apple's platforms, and well not run on anything else. Now, I'm fine with Apple-specific frameworks and GUI frameworks (like QuickTime or UIKit) being Apple-only, but I'd really love to use the language to write a backend service, for which I'd only need Foundation & libdispatch, for example.
- rudiger 14y ago- It takes the right approach to memory management. Realizes that garbage collectors are abominations, and that managing memory is really the job of either the developer or the compiler. Please elaborate why Objective-C's approach to memory management is Right, and why GC is Wrong.
- SeoxyS 14y agoBecause memory management is something that's known at compile time, and doesn't need to be evaluated at runtime. It's the same reason a compiler will essentially substitute the expressions `2 + 2` to simply `4` and save the extra CPU cycle. Most GCs do a barely acceptable job of managing memory, and often lead to hard-to-diagnose bugs. With manually managed memory, you know exactly what's going on and can easily inspect what's actually going on by diving into a debugger. You're also not wasting memory letting the runtime hold onto things you don't need anymore, or wasting CPU cycles trying to figure out what's still needed. Additionally, and importantly, without manual memory management, you cannot safely use pointers and memory directly. The whole idea of playing with memory directly by doing `void buffer = malloc(100)`, and being able to do pointer arithmetic such as `(buffer + 99) = NULL` goes out of the window. Lastly, Automatic Reference Counting is awesome in that it brings you all the benefits of manual memory management (not having to worry about making mistakes, and saving yourself a little typing) without any of the drawbacks.
- flatline3 14y agoI'd just like to touch on GC vs ARC/RefCounting, and leave the buffer mangling for another comment. There are advantages and drawbacks to GC vs reference counting (whether manual or automated), but the disadvantages of GC certainly do not include doing "barely acceptable job of managing memory, and often lead to hard-to-diagnose bugs." I'd provide a more complete rebuttal, but lacking any specific examples, I can only definitively state that GC significantly reduces the likelihood of having to debug memory related issues, especially tracking down leaks due to reference cycles. In comparison to GC, the main advantage of reference counting systems is that they are deterministic. However, they do a lot of book-keeping that is expensive in aggregate and may not even be necessary in a garbage collected system. There are GC designs that mix GC and reference counting to achieve the best of both -- another poster in this thread provided a link to some papers on the subject. The major downside to reference counting -- other than the expensive-in-aggregate book keeping mentioned above -- is, as mentioned above, that they can't handle reference cycles. On iOS it's terrible easy to create cycles, and prior to the introduction of __weak, it was almost impossible to build thread-safe code that also involved a cyclic reference, due to it being impossible to invalid another thread's reference to your object (short of hacking out your own zeroing weak reference implementation, which is what people were forced to do). This ease of creating cycles, especially with blocks and GCD, leads to a proliferation of careful and manual application of __weak designators on self-references. Instead of simply using an instance variable from a block, you must be certain to only access it through a __weak-marked references. Additionally, you now have to worry about NULL-dereferencing! Example: __weak MyObject *weakself = self; _block = ^{ // Whoops! weakself could be nil here. Should have used a property, // which would have just passed a nil argument to runWithTX. Whoops! [opManager runWithTX: weakself->_txid]; // Also, weakself could be deallocated *after* the above call succeeds, // so what we really needed to do as a first step in the block was // capture a -strong- reference to weakself, and return immediately // if we'd been deallocated MyObject *strongSelf = self; if (self == nil) return; // Whoops, accidentally referenced self via _txid below, // causing a retain cycle NSLog(@"Running with _txid=%@", _txid); }); This is awful. If the language used a hybrid ARC refcounting with cycle breaking, that code would simply read: _block = ^{ [opManager runWithTX: _txid]; NSLog(@"Running with _txid=%@", _txid); });