Opinions on C# and .NET


After my recent exposure to C#, I thought I’d write up my thoughts about it and .NET. These will all mostly be in comparison with Java, rather then Ruby – since the implementation is a port of a Java project.

C# and Java started out very similar to each other. They still are, really. But they have grown in different directions. Some things are very nice, some things seem nice, but I didn’t use them, and some things are really problematic. When reading this, I might come of as harsh on C# and .NET. That’s not really my intent – Java and the JVM has its problems too, and I wouldn’t dare to suggest whether C# or Java is better.

The largest difference between C# and Java that really made a large change for me was that C# doesn’t have local anonymous classes. Java has, and these are highly useful. Of course, C# has delegates with lambda expressions instead, and they solve much the same problem. But there are two problems with delegates that make it impossible to use them for all cases. First, an anonymous type in Java can implement several interdependent methods. You can factor behavior local to that piece of code. That doesn’t work with delegates. Instead you’ll have to resort to ugly hacks (in Ioke I make each NativeMethod have references to two different delegates that interact with each other). The second problem is once again the question of intent. I spoke about this in the last post, and I will mention it again. Interfaces are about intent, and they get less useful if you can’t express intent well with them. That’s why the generic Func delegates might not be a good solution in all cases.

The second thing I noticed was the proliferation of “primitive” types. I knew at some level that C# had unsigned and signed versions of things, but I’d forgotten it. It’s actually pretty nice to have those available.

Enums in C# are quite bad compared to Java. The main distinction is that they are based on integers. This gives some fairly strange results in some cases. The one that really bit me was when I forgot to give a default value to an enum field – and expected the default to be null. That isn’t true. The default value for an enum will be the value in it that maps to 0 – which is usually the first element of the enum list. I recommend people using enums to always explicitly init them.

Extension methods seem very useful, and they have been used to add some really nice things in the .NET core library. That said, I didn’t use them for my implementation, so I don’t have any real experience with them.

One thing that really surprised me about .NET was that there is still no support for arbitrary precision math – neither big nums nor big decimals. I ended up implementing that myself, so now there is at least one open source library with liberal license that people can use.

Same thing with regular expressions. The implementation in .NET obviously works, but there are too many incompatibilities in the implementation. Especially the handling of named groups is so different I couldn’t get it to work for Ioke. I ended up implementing NRegex, which is a perl5.6 compatible regular expression engine. It supports named groups, is thread safe, supports look ahead and look behind, and is compliant with level 1 of Unicode Regular Expression Guidelines.

At the end of the day, it was an interesting experience, and nothing surprised me that much. Not really. Most of the things are nitpicks. If it weren’t for one small detail…

Namely equality and hash codes for collections. Why in the name of anything holy doesn’t .NET provide implementations for Equals and GetHashCode? In this day and age? Even if it was a mistake from the beginning, why couldn’t they have fixed that when adding the generic collections? I don’t expect to have to implement these things myself. I especially don’t expect to have to provide my own subclasses of any collection I need to work with. This seriously annoyed me, and made the whole thing take some time, since the bugs produced by it was very hard to pinpoint. And oh yeah, when we’re talking about collections, it’s good to keep in mind that ArrayList.Sort is _not_ stable. It’s using quick sort. If you want a stable sort you’ll have to implement a merge sort or something like that for yourself. This also came as a surprise to me, but it was easily found at least. Since I had a pretty good test suite… =)

Anyway. That’s it.


8 Comments, Comment or Ping

  1. Casper Bang

    Interesting overview. Here’s what went through my mind while reading. :)

    > The second thing I noticed was the proliferation of “primitive” types.

    C# gives you the choice of value types, incl. structs, when you deem it necessary for performance reasons.

    > an anonymous type in Java can implement several interdependent methods.

    C# has delegates and lambdas, they are different. Doing everything by interfaces is often too strict a contract, how do you implement two interfaces that defines a similar method signature that needs to be handled separately? And even if the signature is different as with Comparable and Comparable you are still in trouble!

    > Enums in C# are quite bad compared to Java.

    That’s true. It’s worth noting perhaps though, that we had to live a full decade with various pseudo-enum patterns (have at look at SWT) in Java before we got Enum in Java 5. On a related note, the Java Enum carious the annoying limitation that it can not forward reference itself (except in the Eclipse compiler which is more lax).

    > there is still no support for arbitrary precision math – neither big nums nor big decimals.

    But there IS literal support for decimals to use rather than the torturous BigDecimal library of Java. And with operator overloading, it’s somewhat easier to delegate arbitrary precision math, complex number math, matrix math etc. to external libraries (where imho. it belongs).

    Looking forward to your visit to Denmark.

    April 21st, 2009

  2. Casper Bang

    The sanitizer stripped out my generics declarations, with square brackets it becomes Comparable[String] and Comparable[Integer] instead.

    April 21st, 2009

  3. MLeoDaalder

    There are versions of QuickSort that are stable, Collections.sort in Java is a quicksort variant/hybrid that is stable (if memory serves that is).

    April 21st, 2009

  4. Agree on .NET collections. They are specifically designed for concrete use, and not particularly pleasant to use in a generalized way via interfaces outside of IEnumerable. Equality / hashcode of collections applying to the collections themselves, rather than the contents, is a design choice that I’m not 100% sure is wrong, though.

    Disagree on C# enumerations. They are extremely close to C enums and their use follows a similar pattern, so IMHO they are not really directly comparable. The [Flags] attribute works well for a C-style bitset. The way defaults work is that you define the default enumeration member first, or equal to 0; and it’s recommended that you do the same thing for value types (struct in C#). Of course, C# enums predate Java enums.

    From what you describe, it sounds like you did little more than write Java transliterated into C#. C# has many interesting features beyond Java that I find it deeply painful to use Java, particularly wrt. IEnumerable and monadic stream composition, iterators, a nice syntax for lambdas, value types (v. handy when you need them) and unsafe code (indispensable for awkward performance corners and deep OS integration).

    For example, consider a lexer implemented as a transformation of IEnumerable of char to IEnumerable of Token, for some token. Consider then, a function taking an IEnumerable of T and returning an IEnumerable of T, where the result is the IEnumerable argument evaluated on a separate thread. Two simple composable parts, and you can have a multithreaded lexer.

    Having a nice syntax for lambdas is not to be underestimated. Given a choice between Java’s anonymous inner classes and C#’s lambdas (including statement lambdas and anonymous delegates), I’d rather have the lambdas. The savings in verbosity for implementing things like laziness when you need it is pretty nice.

    April 21st, 2009

  5. raven

    .NET 3.5 was planning to introduce BigInteger, but they weren’t satisfied of the implementation so they cut it before .NET 3.5 shipped. It’s said that it’ll be back in .NET 4.0, so we’ll just have to wait and see how that works out.
    Implementing something that might get into the core library soon is pretty frustrating, I guess.

    C# enums, coupled with extension methods, can have a look and feel much alike its Java counterpart. It’ll take some more work, though. C#’s enums are handy when flags are needed, but Josh Bloch sure won’t agree on C#’s way : )

    If something were designed in Java and then ported to C#, idiom differences are going to be troublesome. Perhaps a cleaner way would be doing some redesign to fit in idioms of the target platform. I’d say this is especially the case for multiple-method-anonymous-inner-classes.

    April 22nd, 2009

  6. Kaveh Shahbazian

    Since I love io coding feel, to have ioke on .NET is very interesting to me. I just want to mention / which is based on io too and added some features to io that maybe are of your interest when revising ioke in future versions:
    # Lightweight objects
    # Lua-like table datastructure
    # Fast small integers
    # Hook into slot lookup for added flexibility
    and maybe other things.

    Thank you for ioke.NET! :)

    April 22nd, 2009

  7. Dan Randolph

    Good point about QuickSort.

    The fastest sort I tested was C++ STL’s sort. The C lib qsort runs at a comparable snails pace (average case). I once had a 50 MB file of integers that seemed to be hitting the worst case for an actual customer of ours. I estimated that it would take two weeks to complete the sort. I never did let it run to completion. I added a call to randomize the buffer before attempting to call qsort. It did the trick, but I wish I’d have converted it to eliminate the qsort function. This is probably what makes Array.Sort “unstable” with duplicate keys.

    Fortunately there is the PowerCollection to solve this problem
    /Release/ProjectReleases.aspx?ReleaseId=6863

    July 17th, 2009

  8. Hi,

    I was gonna try out your Ioke.Math stuff, but the git website looks not very stable, the download tarball isn’t working (FF 3/IE 7). Also in the Issues tab I can’t “create a new issue”, nothing happens.

    Also can you recommend a book on exact arithmetic? I want to start experimenting in the field, so I’m looking for guidelines on how to design big integer/integer fraction classes.

    Best regards,

    Wout

    October 10th, 2009

Reply to “Opinions on C# and .NET”