I hate Obj-C with a fiery passion. My single biggest issue with it is that it simply does not make my life as a programmer any easier. On the other hand when I work in C# I am constantly amazed at how damned easy the language and the libraries make my life.
Not once when using Obj-C have I ever said, "Wow, that was so easy thanks to Obj-C!!!" I am more likely to curse the heavens as to why the debugger can't show me the contents of any basic container type.
Going forward my work will be as heavily cross-platform C++ as I can make it. The UI may be done through platform native interface constructs, but everything I can possibly make C++ I will.
What you care to provide an example? Are you referring to not being able to mouse over a var during debugging and having it displayed properly? I've never minded having to use gdb to type out "po items", but can understand that if you're used to mousing over and getting vars it would be annoying.
I don't disregard your perspective, mine is just exactly the opposite (I would prefer ObjC/Cocoa to C++/<Framework of your choice>, no contest).
My perspective is one of a PC/console game background who works on iOS stuff on the side. The transition from VisualStudio/C++ to Xcode/Obj-C is eye stabbingly awful.
Obj-C can absolutely accomplish most anything that C++ can, but I don't think the language makes of it easier. Once you've learned that GDB even exists and figured out many of the strange syntax nuances it's passable, but in my opinion not easier.
By comparison going from C++ to C#, Lua, or Python (my personal experiences) is astonishingly easy. Not just easy at first but continuously surprising at how many wonderful things you can do and how easy it is. As I said in my root post not once have I ever said "holy shit Obj-C sure made this task easy!"
Fair enough, and I can certainly empathize with wanting to use C++ so you don't have to rewrite everything for another platform. My perspective is going from the C/C++ (on Visual Studio for the most part) I used in school (so none of those nifty libraries/frameworks), to (for the most part) working on a data driven mobile application for iOS/Android. And after working with the Cocoa frameworks, I did say "Holy shit, Cocoa sure made this task easy!" :)
>Once you've learned that GDB even exists and figured out many of the strange syntax nuances it's passable, but in my opinion not easier.
You can mouse over an NSArray or NSDictionary and see its size and contents. You're not as familiar with the tools.
I have your same complaint, but about C++. I'm frustrated that I can't easily see the contents of a std:set or std:map in xcode. I'd be thrilled to find out if it's just a gap in my knowledge, though.
An NSMutableArray full of nothing but NSStrings will not display the string values of those strings on either mouse over or the locals view. I can see the number of strings but not what those strings actually are.
Are you comparing Objective-C to C# or C++? Those are two completely different beasts.
I find Objective-C refreshing when compared to C++ ( take inheritance for example...in C++ I need to redeclare functions I'm overriding from my base class. Every change needs this. What a pain! Not so in Objective-C).
Having said that, I can't say how it compares to C#.
As someone who also used to really dislike Objective-C and also likes C#, I would urge you to reconsider your opinion about Objective-C. It's really not a bad language. It makes different trade-offs than C#, but I think once you understand the "philosophy" behind the language, chances are that you will discover that it's actually a pretty good tool for certain tasks (at least this has happened to me). I agree however that the current state of debugging Objective-C code is simply atrocious. I really hope that Xcode will address that soon.
As someone who spends most of their time in Xcode doing Objective-C work, I find the debugger to be particularly delightful. Between the gdb/lldb shell, mouse-over displays, variables view, "automatically run in the debugger when I set breakpoints without needing to be in a special Debug mode", the Static Analyzer, and Instruments, I find it to be a treat.
What do you find atrocious about it? Perhaps it's something I'm missing as I haven't used Visual Studio's debugger in forever (or Eclipse, or Qt Creator)..
I have no complaints about the static analyzer and Instruments; they're both excellent tools. The debugger is stuck in the 80's, it's essentially GDB with a very light GUI rigged on the top of it. It doesn't allow for things like easy exploration of data structures; the complaint by the OP is very legit, you shouldn't have to jump through hoops just to see what's going on in an NSArray. The very fact that NSLog is so common in Objective-C code (and not used for error logging purposes but for debugging purposes) is indicating that it is very difficult get any useful information out of the Xcode debugger. Not to mention the lack of advanced features such as Visual Studio's historical debugger that can be very very helpful.
I've never really programmed in C++, but I have to say (as an iOS developer who's programmed in Java, Basic, C# in the past) I love Objective-C. It's really easy to write good, object-oriënted code in the language and it got so much better with the release of iOS 5 and the new SDK, especially because of ARC. I'm not sure if C++ has anything comparable to ARC.
In C++, you have std::shared_ptr (or boost::shared_ptr and many others) which do automatic reference counting (although you specify it explicitly that these pointers have automatic reference counting; there is no way to simply enable it for all raw pointer types).
This is an interesting (though incredibly dated study) from an academic standpoint because both languages are supersets of C and represent two different lineages (Simula vs. Smalltalk). That said a more modern and useful study might be a set of comparisons between Objective-C and Java, since they are the current mobile dev languages of choice.
The thing that this 1997 is missing is the retain - release mechanism, found "only" in classes, that are derived from in NSObject, and still a key Obj-C feature.
I don't really know when exactly was this added to NeXT/Cocoa API, but I think it's important to note.
So, I guess python, perl, and ruby would lose a contest to COBOL which has a ANSI / ISO standard[1] and is available across multiple platforms? I think implementation based standards have a place.
Technically untrue, C++ is a standardized language, the standard was created after the language. Ada is a standards-based language. So's haskell. The first C++ implementation (as well as "The C++ Programming Language") were released in 1985, while the first C++ "standard" was released in 1998 (ISO/IEC 14882:1998).
> available across multiple platforms and the other one isn't.
Objective-C is available on pretty much any platform on which GCC or Clang runs, actually.
For most people, what makes Objective C so useful though is the Cocoa core classes. The GNUstep stuff has a lot of that functionality, but is not quite what the Apple stuff provides.
Obj-C is an open standard language. Foundation is a proprietary library with some key stuff even PATENTED by Apple (for example, the AutoRelease Pool falls into some of the Apple patents).
Is there any actual incompatibility that prevents building an Objective-C runtime for NaCl, or is it simply a matter of ObjC not being included by default?
I've been thinking (warning: pure speculation ahead) that I could target my binaries to LLVM IR and then use the highly-experimental PNaCL. But who knows how long it will be before that is viable.
This is pure speculation, but its possible that the runtime does some tricks for performance (possibly in the method dispatch routine) that the NaCl sandbox doesn't allow.
The lack of destructors and constructors makes Objective C miss an entire galaxy of functionality. That the language authors and programmers don't sorely miss this feature is a testimony to the limited understanding they have of programming. Lack of destruct-when-I-leave-scope makes real exception semantics impossible, and no "smart" objects that clean up after themselves meaning it's impossible to create abstract data types with such limited features. Programmers who don't miss these features I call "flat programmers" because they are missing an entire dimension in their code. They are forever having to understand the details of their implementations instead of being able to package up functionality from initialization to destruction in abstract terms. Don't bother trying to explain any of this to them. People don't understand what they don't understand. They don't even know what they are missing. But I suppose this is appropriate for Apple programmers who are more concerned about which pixels appear in a drop down list box than the overall job their program is attempting to do.
Ad hominem attacks aside, let me address your points.
Firstly, destruction upon leaving scope in Objective-C would add some magic unexpected behavior that doesn't conform to what we expect from standard C stack-based functions.
In C++, when an object is normally declared, it exists on the stack, therefore it will disappear when the scope ends. The fact that the destructor is called is nice.
In Objective-C, all objects exist solely on the heap. All object-orientation is done at runtime, not at compile time, which leaves it open to be a lot more dynamic and open to fiddling at run time than C++ is. This of course loses a lot of the speed that C++ has, but it's not a big deal in most standard applications.
Since creating an object requires specifically allocating it on the heap, having it destruct when the pointer leaves scope is no good. That kind of magic behavior is exactly what would lead to awful bugs in Obj-C. If you want short-lived objects, you call their autoreleased constructors, which means they will self-destruct next time the thread's event loop ticks. It's an extremely common pattern, and happens so often in code that you don't, as you claim, 'have to understand the details of the implementation'.
And there's absolutely no need for the derision in your post. Please make your points and defend them like a civilized person.
Your diatribe would have been slightly less absurd had you realized that this article described what Objective-C was like fifteen years ago: indeed the article predates OS X. Things have changed.
I'm not an expert on Objective-C, but I think this article was bad and dated even in 1997. It doesn't mention reference counting, uses -free instead of -dealloc, and seems to consider ANSI C as relatively new and optional, which means the author was either years out of date, or was arbitrarily ignoring some language features that he considered to be part of the NextStep system instead of the core Objective-C language.
#include <cstdio>
#include <functional>
using std::printf;
using std::function;
function<int ()> f(int x)
{
function<int ()> g = [x]()
{
return 2 * x;
};
return g;
}
int main()
{
auto f1 = f(5);
auto f2 = f(6);
printf("f1() = %d, f2() = %d\n", f1(), f2());
return 0;
}
(Which prints `f1() = 10, f2() = 12`)
Or did you mean nested functions in the sense of being able to form named closures so that they can call themselves with a headache? It is admittedly more or a pain to do that (if you want to return a closure), but it is still doable, using new and delete:
#include <cstdio>
#include <functional>
using std::printf;
using std::function;
function<int (int)>* f(int x)
{
function<int (int)>* g = new function<int (int)>();
*g = [g, x](int n)
{
if(n <= 0)
return 1;
else
return x + n * (*g)(n-1);
};
return g;
}
int main()
{
auto f1 = f(0);
auto f2 = f(1);
printf("f1() = %d, f2() = %d\n", (*f1)(5), (*f2)(5));
delete f1;
delete f2;
return 0;
}
This must be the 9001st time I read a post by a C++ programmer that doesn't understand that the problem isn't that other languages don't have RAII. The problem is that C++ doesn't have finally/unwind-protect and thus requires RAII to approximate it.
> The problem is that C++ doesn't have finally/unwind-protect and thus requires RAII to approximate it.
I don't agree with this statement, at least for finally v RAII: RAII is far superior a tool to deal with scope and resource management, as it requires less work on the part of the resource user and is as a consequence far more secure. It also ties in with C++'s memory semantics and therefore exists "for free", which is nice. Even more so in as messy a language as C++.
RAII has issues, one being composition (a subject on which `finally` is worse, not better) and the second one being "in-place" operations, which `finally` can handle but — at the end of the day — should probably be implemented separately.
`unwind-protect` handles both case very nicely and is therefore — as far as I'm concerned — superior. Although it has an (easily dismissed) "inconvenient" over RAII of adding a special form to the language.
Smalltalk's `BlockClosure#ensure` is also quite nice in that department, though I'd say slightly inferior to `unwind-protect` as building on it is more expensive.
I would use RAII even if it weren't required for C++ exception safety. RAII is convenient and it allows you to write code that is smaller and more solid than it would otherwise be (with or without a "finally").
I've looked over what unwind-protect does and to me it doesn't do more than what you can do with a custom RAII like class.
The key thing is that it acts like a wrapper around a try/catch/finally-like block (including other forms of flow control), while allowing you to put arbitrary code in the execute and cleanup portions. You would get the same effect with RAII, most of it would be taken care of for you with the right RAII classes, and if you needed custom code then just write a custom RAII like class or be smart about handling it.
Although the C++ version wouldn't handle C's longjmp and also goto's. But if you use them you're not exactly coding in C++ then.
Not just longjmp and goto, but Objective-C's @throw.
As much as I'm a fan of RAII in C++, it really is a "pure C++" idiom. If a C++ class is needed in Objective-C code that can @throw an NSException, then the C++ cleanup code really has to be invocable explicitly (because the destructor might not be called). For example:
Not once when using Obj-C have I ever said, "Wow, that was so easy thanks to Obj-C!!!" I am more likely to curse the heavens as to why the debugger can't show me the contents of any basic container type.
Going forward my work will be as heavily cross-platform C++ as I can make it. The UI may be done through platform native interface constructs, but everything I can possibly make C++ I will.