This may come as a surprise for some people, but I’ve been using C# and Objective-C both for almost exactly as long (between three and four years). What you might call my current day job is comprised of writing C# code.
Here’s the thing with .NET. .NET is great. It’s not great as the One True Platform for Windows development. On the other hand, it’s not “great for something that’s from Microsoft” either. It is great on its own merits, perhaps, and it is a shame that its merits are so tightly coupled to provide an excuse for C# to exist, because they are each shackled to eachother.
.NET is now, and has been for a while, at least perceptibly noticeably faster than Java. I’m personally way better off with C# than with Java. What I think I’m doing at this stage is establishing that I really quite like .NET and C# both, and that even if I didn’t, I’d think they were more than reasonable efforts for a technology-of-the-week company like Microsoft.
That said, there’s a big technology – and philosophy – divide between C# and Objective-C, and between .NET and Cocoa. Coding in both of them means that I’m soaking both my feet in water of different temperatures. I am in a fairly unique position to stand with one foot in a bucket of cold water and one foot in a bucket of hot water and announce how, on average, I’m feeling pretty good. To wit: When I’m in C#, I end up missing Objective-C. When I’m in Objective-C, I end up missing C#. Here, therefore, are some reflections, most prompted by a chat I had with Scott earlier today.
I love generics. This appeared gradually and surprised me at first, but it’s quite true. Generics, if you don’t know, means that you can supply types to classes when using them – like
List<string>orDictionary<string,int>– and have instances whose methods change to accept those types. I’m generally firmly in the duck typing camp, but C# and Objective-C both need compiling, and when there’s a compiling stage, you can get warnings and errors. The Objective-C code for storing, say, a string in an array, makes it impossible to know when you’re passing in non-strings without doing type checks manually beforehand, or creating tuned methods that only accept the given type in order to generate the standard compiler error.C#:
List<string> strings = new List<string>(); strings.Add("xyzzy"); // takes only strings strings.Add(15); // compiler error string x = strings[0]; // guaranteed to be a string // or non-existant (yielding an exception) strings.Remove(0);Objective-C:
NSMutableArray *strings = [[NSArray array] mutableCopy]; [strings addObject:@"xyzzy"]; [strings addObject:[NSNumber numberWithInt:15]]; string x = [strings objectAtIndex:0]; [strings removeObjectAtIndex:0];The previous example brings to mind another wider look at the same subject – lists. In Objective-C, you get a fairly simple choice for an array: mutable or immutable (default). Being the strict C superset that it is, you can also drop down into C arrays and pointer trickery.
C#, on the other hand… Someone at Microsoft enjoys having a dozen deceptively similar – but ultimately all a little different – ways to solve this problem.
At the bottom end, you have C# arrays, which are similar to C arrays. They are fixed-size and immutable. They’re also alone in being natively initializable via literals. A low-level class,
System.Arrayhandles the juggling, and eachArrayis typed for a specific type but using a special, C array-like syntax (string[]), instead of generics syntax. This is because generics were introduced in C# 2.0 and .NET 2.0, and theArrayhas been along (with the same special treatment) since the very beginning.Slightly above C# arrays are non-generic lists. The
ArrayListis an almost perfect parallel to Cocoa’sNSMutableArray– something that stores only objects. You can store anything in anArrayList. These were the only mutable all-purpose lists in .NET 1.0 and 1.1.Above
ArrayListlie generic lists –List<T>, whereTis to be substituted to a type you pass in when you instantiate, subclass from or otherwise use the class.So far, so good. What’s wrong with the hierarchy is everything above this point. Imagine for a second that you have a control called a ListView. (Hint: Microsoft does.) Imagine further that you want a property inside to return the list of items for your pursual. Imagine also that these items are all of class ListViewItem. If you were Microsoft, you might want to use, simply,
List<ListViewItem>. Too bad you’re not Microsoft, and too bad ListView was around in .NET 1.0, way before generic lists.In these kinds of situations, there are special purpose lists (belonging to some sort of fuzzily defined grouping called Collections meaning basically “objects that have other objects in them”). In fact, there are fields, endless fields, where Collections are no longer being born, they are grown. So what do you end up with?
ListView.ListViewItemCollection– a special-purpose class if you ever had one – specifically designed to holdListViewItems. To be fair,ListViewItemCollectionhas at least one speciality – that of being able to accessListViewItems by passing theirKeyproperty as the indexer – literally likecollection["key"].Just having several hundred very special-purpose classes isn’t a valid point of criticism, though. The strange thing is that many of them drop (or choose not to implement) small parts of functionality. Some might not ‘do’ enumeration (the technology that enables
foreachloops), some might leave out Contains-like functionality to check for the existance of a value. It’s all very confusing and a very poor and uneven experience for the programmer, especially since the class’s raison d’être is often deeply hidden in the documentation, if mentioned at all.As much as I like generic lists, I despise most of the rest of the trickery.
Boxing! C# gets boxing (wrapping non-objects in objects) right –
intanddoubleandstringand friends are supposedly primitives, but are surprisingly well-mapped back and forth to real classes to the point where you really can’t tell unless you’re profiling. In Objective-C, on the other hand, the boxing process is entirely manual, like:NSNumber *integer = [NSNumber numberWithInt:8]; int x = [integer intValue];C# has constructors. Objective-C has alloc-init method pairs, designed to be called in a chain, or class convenience methods for doing both and returning an autoreleased object for you. When you call a constructor in C#, it first creates the object for you and then calls the appropriate constructor, whose objective it is to set up the object, already assigned to
this. In Objective-C, you’re responsible for returning the objectself. In both languages, you’re responsible for calling the appropriate superclass constructors.The C# way involves less manual labor and book-keeping. In Objective-C, you can return an object that has already been initialized, say, if you’re keeping a cache of objects not supposed to be created twice, instead of the object just created.
There’s no correct answer, but the different approaches will be sure to have you curse at one time or another.
The class models in C# and Objective-C are vastly different.
Objective-C has bona-fide class methods, eligible for specification in Objective-C protocols. C# has static methods, not eligible for specification in C# interfaces. Objective-C does not have class variables, but it does inherit static variables from C, which works almost the same. C#’s doodads are also called static variables. In Objective-C, no instance variable can be assigned immediately on declaration, but must be instantiated in the init instance method; in C#, both static and instance variables can be assigned immediately, and to the return value of any statement, including functions. (Since Objective-C inherits C’s static variables, you can only assign literal values to them on declaration, and not return values of methods or functions.)
C# has dynamic dispatch off by default – it’s opt-in by the use of the
virtualkeyword in the method declaration and theoverridekeyword in the ‘overriding’ method. Classes can be prevented from containingvirtualmethods by being declared with thesealedkeyword. It’s also possible to declareabstractclasses, which haveabstractmethods that have to be overridden and use dynamic dispatch. Objective-C has dynamic dispatch on by default. (Dynamic dispatch is being able to define the methodfooin classA, introducing classBthat inherits from classA, implementing methodfooin classB, and having classBcalled when you call the methodfooon classB.)Finally, C#, like Java before it, and Objective-C before it, uses a policy of one superclass, n interfaces/protocols. In Objective-C, the way of specifying an interface type is
ObjectClass<Interface>; in C#, it’s justInterface. (C# has one root class,System.Object, which everything implicitly inherits from by default; Objective-C allows defining new root classes and provides theidkeyword – in actuality the runtime’s data structure of an object – to specify ‘any object whatsoever’.)
There’s a lot of ground to cover on C# and Objective-C, and on .NET and Cocoa. The origins and fates of .NET and Cocoa are, dates taken out of the equation, remarkably similar: objective-oriented juggernauts gaining traction with smaller and newer apps, but largely failing with the cross-platform market and the big, heavy, thousand-year apps.
What best sums up my feelings about Objective-C and C# is this: Objective-C+Cocoa is smaller and better defined, and scores a higher average level on the graph. However, C#+.NET’s extremes – both good and bad – are more pronounced. At its best, it’s above Objective-C+Cocoa by a good deal; at its worst, it’s right down the chasm with no hope of improving.
I am certainly hoping that both teams are watching each other with open minds.
[…] Jesper: That said, there’s a big technology – and philosophy – divide between C# and Objective-C, and between .NET and Cocoa. Coding in both of them means that I’m soaking both my feet in water of different temperatures. I am in a fairly unique position to stand with one foot in a bucket of cold water and one foot in a bucket of hot water and announce how, on average, I’m feeling pretty good. To wit: When I’m in C#, I end up missing Objective-C. When I’m in Objective-C, I end up missing C#. […]
By Michael Tsai - Blog - C# and Objective-C · 2007.03.31 01:12
What is it that you miss about C# when working in Objective-C?
By http://chanson.livejournal.com/ · 2007.03.31 04:44
I miss a lot of things from C# in Objective-C, and I miss a lot of things from Visual Studio in Xcode.
Some things I miss from C# at the top of my head are generics (or at least being able to quickly make new dicts or lists containing specific types, be that implemented through generics or a class generator or what have you), declaration assignment of instance variables, being able to get a key-value pair instead of just the key when enumerating a dictionary and automatic boxing of primitive types. I fully understand that these are not easy things to fix – except maybe for key-value pair enumeration.
The half of Visual Studio that’s not universally dreadful is actually quite charming. The IntelliSense implementation in my experience completely blows Xcode’s Code Sense out of the water. It’s rock-solid and fast on a machine half as powerful and twice as occupied as my MacBook whereas Code Sense is slow and has the tendency to become corrupt over time. Being able to hover over a method call and seeing the method declaration and being able to move between parameters and seeing the method signature with the current parameter bolded are two things that are not in Xcode which I deeply wish they were. IntelliSense in Visual Studio under Parallels is actually more fluid than Code Sense in Xcode.
Refactoring is also nicely handled, although I have no clue how these features will be in Xcode 3.
By Jesper · 2007.03.31 08:33
NSArray *strings = [NSArray array]; [strings addObject:@”xyzzy”];
You cannot add objects to NSArrays. NSMutableArrays are required if you want to remove objects, but also if you want to add them. Or have I missed anything?
By http://helgeg.myopenid.com/ · 2007.03.31 09:29
As a daily user of Visual and Xcode, I have to say that Xcode has a superior support for code navigation, Visual is still limited by old design to navigate through a huge code base.
Xcode allowed me to navigate my huge Windows C++ code without compiling it, while Visual can’t help you until you made your code compiled.
By igerard · 2007.03.31 09:56
helgeg: you’re right. Fixed.
igerard: I’m in love with Xcode’s “symbol” popup list, where declarations, definitions and
#pragma marks show up. It’s definitely one thing I’d steal away.On the other hand, Visual Studio has excellent code navigation! Right click and choose Go To Definition (in Xcode as exactly that, or cmd+double click) to skip to the definition, even in classes for which you don’t have the source (you’re shown cached metadata). Right click and choose Find All References and you see every part that specific object is being called. It’s sort of in Xcode (Find Symbols), but it’s not as obvious and I’m not bringing myself to use it. Visual Studio also had back/forward memory to go to where you just were in that other file (tabs!) with Ctrl+- and Ctrl+Shift+- (at least that’s the effective swedish keymap).
I’d agree that Visual Studio may suck at times for relying on code that compiles for many of its features, but it also does provide a more robust implementation of those features. I haven’t seen your project, but I’ve been able to jump around instantly in projects with lots of classes, source just fresh out of the repository and unbuilt – maybe the C# or .NET experience is way different from the C++ experience, though.
By Jesper · 2007.03.31 10:24
[…] the whole article at the “Waffle” […]
By b.l.o.g. » Comparison of C# and Objective-C · 2007.03.31 11:05
My code base is C++ and very hudge with to many .h (Windows, Qt, Xerces, Xalan, Orbacus, RepEase, SpredDesigner …) and Visual is lost finding reference 70% of the time I need it…. Copernicis my friend :)
I agree that the feature in Visual to remember where I was the last time is a vry nice feature.
The way Visual allow me to navigate through my files is very very bad when compared to Xcode, the search field in Xcode is very very useful.
This is nothing to do with .Net, I am using them very rarely, and I find the class to big with bad naming, sorry.
By igerard · 2007.03.31 12:20
igerard: Fair enough. I haven’t done non-.NET development in Visual Studio, and so I obviously don’t have the same experience with it as you do.
There’s obviously a trend in the development of Visual Studio itself to base it more on .NET and gear it more towards .NET development, so I wouldn’t be surprised if its offerings towards ‘pure’, Win32- or MFC-based programming was basically the same as it was a few years back.
By Jesper · 2007.03.31 12:43
It would be more appropriate to say that C# joins Java’s Objective-C like policy of one superclass, n interfaces…this is one of the many design decisions which the Oak/Java people based on what they saw in ObjC (a number of the Java language and API developers went over from NeXT, or worked for third-party NeXTSTEP software companies like Lighthouse).
By http://frodomorris.livejournal.com/ · 2007.03.31 16:30
I am fully aware of how Objective-C predates, and inspired, Java. However, if I’m explaining both C# and Objective-C, Java’s the only language left. I’m pointing out similarity, not originality.
Saying, for example, “FreeBSD, like Ubuntu Linux, offers
bashas a shell” doesn’t imply that Ubuntu Linux came first.By Jesper · 2007.03.31 17:37
Nice article. I’ve been toying around with the idea of using Objective-C protocols to mimic generics. e.g.:
NSArray* myArray;
Protocols and class names live in separate namespaces, so this is entirely feasible. If you like, you could prefix or suffix the protocol name with some characters to make it a little bit less ambiguous:
NSArray<NSString>* myArray;
I haven’t tried it in practice yet since it’s not really in-line with Objective-C culture, but I’m considering it for my own projects. I hate maintaining code with no generics: “NSArray? What on earth is this in NSArray of?”
(And yeah, Visual Studio’s IntelliSense rips all over Xcode’s Code Sense. Let’s hope Xcode 3 improves its game!)
By André Pang · 2007.04.02 02:35
Nice article, Jesper. I’m enjoying reading more of these kinds of articles, where XCode and Obj-C are compared against VS and M$’s offerings. I have no intention of using the latter, but certainly learning about them is interesting.
By http://openid.aol.com/daveofmacdob · 2007.04.02 03:45
I’ve used all the languages mentioned here. Personally, I think java the way it was before sun got so bloody verbose was superior to C# in a lot of ways, though it was lacking some nice additions like generics and autoboxing. As far as the actual comparing of obj-c and c# goes, both have their pros and cons. I like not having to deal with header files, having generics and good garbage collection, etc. However, obj-c tends to run much faster, compiles to a native code format, so you don’t end up with all the JIT/VM headaches that are possible in the others and is actually very elegant in many ways. I am anxious to see what obj-c 2.0 will bring to the table in real world apps and coding. What I would like is real, solid garbage collection, generics and some other convenience items added into Obj-C, not to mention better exception handling and a much larger library of APIs. Now, moving onto GUI development, MS Visual Studio is a damned good IDE. Actually, as far as I’m concerned, the only thing MS has ever truly made product-wise that is truly good would be their IDEs. That being said, unless you’re doing some quick, down and dirty app development, the overall model used by XCode and Interface Builder is much more elegant and much more Object Oriented in nature… the whole click and code model as opposed to a more realistic MVC. Although, the newer bindings capabilities could use some more polishing, to say the least.
Given my preferences, I would much more prefer to always code in Obj-C than in C#, especially if Obj-C ever got some good memory management (read solid garbage collection), a much more robust and developer friendly library of APIs, Cross OS capabilities (more robust, again, like Java was supposed to have been) and some polishing features. I know I’m looking forward to some of the publicly announced changes coming with the next OS, i.e. project snapshots, properties, foreach style iteration, etc.
This being said, the whole C#/.Net/Mono world is probably here to stay. The building blocks have been around for quite a while and are heavilly adopted. Progress is being made to bring the languages and tools to most every OS (via Mono, etc.) even if it is still slow going and not ready for OS X yet and it is much more robust overall, allowing for web, services, utilities (command line apps), mobile and gui development, which unfortunately we just don’t have or when we do, not nearly to the degree that .NET does, when using Obj-C.
I think a lot of good points have been made above, both in the posting and comments. I’ve used (and forgotten) a lot of programming languages over the years. I think my overall favorites from most to least at this point would probably have to be as follows: Obj-C (Cocoa)/Python (a tie there), then C#.Net (VB Bites), Java, Perl and all others staggering below there. If I could truly compile Python to Native code, I would probably use that as much if not more than any other language due to it’s elegance and the ability to code solid, stable apps so fast, hence it’s tie with Obj-C. Java used to be my favorite language of all time, however it has gotten way to verbose and Sun has screwed up some things in some nasty ways, like introducing a whole new IO library instead of enhancing what was already widely used and adding new features to that and their GUI development has always pretty much sucked.
The one thing all of these languages are missing though is good, easy to use, full control network APIs. They all have wide limitations (unless you want to drop to pure C/JNI/Com/Etc, which is just nasty and doesn’t lend well to good design, maintenance or ease of development).
I have to say though, as a language goes, Obj-C beats C#, as a GUI Development System goes, Cocoa (XCode+IB) beats MS Visual Studio, for overall ease of use and wide library of code to draw from though, C#.Net wins out though. I’m hoping to see this change as time moves on though.
Well, those are my thoughts anyway and like everyone else, I’m partial to them and others will likely hate them, but such is the way of such things.
By Remi · 2007.04.10 20:17
Very good article. Thank you.
By Frank · 2009.04.07 22:30
I just found this blog post. I also have a long history with both Objective-C and C#. These days, I’m the author of a language that counts C# and Objective-C among its ancestors. Like you, I love features from both languages. My language also derives from Python and Eiffel; it’s called “Cobra”.
Like C#, Cobra has generics, declarative initialization of ivars, autoboxing, and C# style constructors and methods. However, Cobra has “virtual” turned on by default–you have to go out of your way to make a method nonvirtual.
Like Objective-C, Cobra supports an “any object type” for which binding is late binding. The name is “dynamic”. When passing a dynamic value where a static type is expected, Cobra does auto-unboxing.
Cobra runs on .NET and is currently being ported to JVM. I hope after that to port it to Obj-C, but that won’t be for some time.
There are other features like first class support for unit tests and contracts, although we’re currently lacking in tooling until someone steps up and takes the lead on it. (I’m always busy on language design and the compiler.)
If you check it out, I would be interested in your feedback.
(Btw, love the Matrix reference.)
By Chuck Esterbrook · 2009.04.30 10:54