I have been using c# for a while now and at first was very impressed with some aspects of it compared with c++. Ironically and must to my surprise, over time I have become more impressed with c++ and have found some basic problems with c#. Lets look at c# and compare it to (unmanaged) c++.
- C# does a few things wrong here. First of all for the sake of language simplicity simply reusing the class would be the most straightforward mechanism to implement stack vs. heap allocation. You would need a way to specify where a class element is being allocated. Obviously the assignment operator would work differently depending on whether you allocated on the stack vs. the heap. C# also restricts the functionality of the struct preventing derivation which only confuses things more.
- C++ allows you to use the same structure to specify stack vs. heap allocation, a truly useful thing. After all stack vs. heap allocation is an optimization element, and not allowing the user to use the same code regardless of where he allocates an object is silly. C++ has special syntax to let the user know whether he is accessing from the stack or the heap and this is good.
2. Having the core language specify one behavior for = and another for == with respect to pointers.
- C# sets the wrong idea by having strings use == not to compare pointers but the actual objects themselves while = always copies pointers. Without overloading == compares pointers. Trying to abstract away pointers to references and then not using them consistently is confusing. What does == do with respect to pointers? Hard to tell if you’re not looking at the source. It seems that if == always compares references (pointers) then it should always simply compare pointers. A .equals or the like would be better suited to testing whether the elements in the class are in fact equal.
- C++ pointers treat = and == consistently and do not allow overloading and this makes perfect sense. When c++ allows separate behavior for non-pointers this also makes sense. How shallow vs. how deep of a copy is a question best answered by an overload because one size does not fit all. Ditto for comparison here.
3. Not having const support. This is very useful in c++ and c# is less robust without it.
3. The lack of templates if an obvious inconvenience as it makes type safe containers among other things very difficult in c# – this is being fixed for c# with generics and will become a non-issue eventually.
4. The lack of the functionality in a c++ reference. A c++ pointer is basically a c# reference minus the syntactic sugar. A c++ reference on the other hand is guaranteed non-null, which is really nice in a world splattered with if(blah!=null). Sure you can “trick out” a c++ reference but not even making it possible to null check a c++ reference is really nice.
I wanted to add that c# doesn’t generate optimized code like c++ however this has nothing to do with the language itself.
Also the visual studio ide does not allow individual files to be built separately – this is a fallout of metadata.
Some things I dislike have more to do with the libraries than anything else. Having global functions disguised as static members is nothing more than syntactic sugar. Sure you can have ctors for statics in c# and this is a minor advantage, but it is still like putting object oriented makeup on a strictly procedural face. I would rather see the language support autoinstantiated classes that were singletons than this. At least there wouldn’t be arbitrary mixing of “stand alone” functions and true functions that are per instance.
That being said c# (and .net) has a very useful standard library something c++ could take some hints from.
The Good Things
1. C# keeps novices from doing bad things. C# is like child safe locks. It keeps novices from opening the doors when it is dangerous to do so. Some of the many things it keeps safe but yet any savvy c++ programmer would know to use wisely:
- The preprocessor goes out the window – thank god for the loss of macros – I have reluctantly debugged way to much code using the obfuscation that is macros much to my displeasure – however a savvy c++ coder knows to avoid macros except in truly extraordinary circumstances like the plague.
- Leaning towards pointers in all cases keeps newbies from falling into c++ traps of non-optimal creation and usage of copy semantics (passing parameters to function that copy expensively).
- Better syntactic sugar support that makes code a little less arcane. Keywords like abstract, override and others keeps things cleaner.
- Generating warnings about unintended overrides of non-virtual functions ( c++ should be doing this).
2. C# has some core elements that benefit everyone that C++ should have as well.
- Garbage collection – obvious but oh so nice. Stroussop has said many times he wants this added to c++ and many tests have shown that in apps with more than a trivial number of allocation that mark and sweep gc is a better performer than typical manual heap based solutions.
- Robust checking for uninited variables and out of range utilizations. Why the stl can’t at least support debug only range checking in most implementations is beyond me.
- Meta data support in lieu of header files – no need to qualify this one – in a world without macros why have header files?
- Static ctors are minor but nice.
- Having the internal access specifier is nice – c++ could possibly use the javaesque internal to a namespace to implement this hiding.
3. Some C# advantages are much more minor but still nice.
- Since pointers (aka references) are used far more often in C# and C++ than anything else not needing to specify * when talking about them is nice, and using . instead of the cumbersome -> is also nice. Of course flipping the semantics in c++ would be impossible at this point but I’d rather use * would talking about a non-pointer version of a class and -> to index that same non pointer would be nice as well.
- Specifying ref when sending a ref to a function so you know it will be modified is nice, not being able to look at a calling function and know what will be modified is frustrating. I would prefer simply using the & operator in c++ or using a plain pointer. The caller doesn’t really care whether the receiving function is using a ref or a pointer unless it is non-const.
- The syntactic sugar of properties is very nice – its funny how important syntactic sugar can be at times.
- Event support is nice but I have found it is misused more than properly used. It can create some ugly spaghetti.
4. C# imposes some things that a more irrelevant than anything else including forcing things into classes. How many c# programs have you seen with static functions everywhere – technically this is still an “improvement” over c++ because of static ctors and hiding data elements but still statics are too much like globals for my tastes.
This is really just a few the points I have thought about lately and surprisingly I have found that (unmanaged) c++ and C# both have pluses and minuses. Preferentially which would I work in?
C# in most cases simply because of the robust garbage collection support, lack of header files and extra error checking. But the optimized performance of c++ implementations combined with templates, knowledge and utilization of “pointers/references” vs. stack allocated objects and their consistent behaviors (vs. c# fuzzy mess there), more ubiquitous language support in the dev community, direct interop is asm when needed (rarely of course) are compelling reasons to end up using c++ far more in the future.
If only c++ supported gc standardly as well as metadata of header files or c# supported intelligent stack vs. heap usage, templates and direct interop with native c++, and ideally better performance the choices would be far more clear one way or the other.
I expect the gap to close between the two, although I feel c# will probably be more responsive than c++ in making smart changes, however some things like structs may be difficult warts to hide over time.