C# 4, part 1: Looking back at the past

Everyone else is speculating about what’s going to be in C# 4 (and various possibilities are coming out of MS), so I thought it would be wise to start my own series of wishlist posts before I miss the boat completely.

In this first post, I’m not going to look at the future at all – I’m going to look at mistakes of the past. When I say “mistake” I of course mean “things I would have done differently had I been a language designer with 20/20 hindsight”. Of course, there’s a lot of room for argument :)

Mistakes in C# 1

  • Lack of separate getter/setter access for properties. This came in C# 2, but it should have been obvious that it was highly desirable long before C# 1 came out.
  • Lack of generics – ish. Don’t worry, I’m not going to claim that all the features of C# 2 and 3 should have been in C# 1, but if generics had been in at the start we could have avoided having the non-generic collections (and interfaces) completely. Mind you, I’m glad that the .NET team took their time instead of including the bodged (IMO) generics of Java 5.
  • Classes not being sealed by default. I’ve believed for a long time that allowing inheritance incurs a design cost (and it’s not like I’m unique in that respect). C# fixed a mistake of Java by making methods non-virtual by default; the same should be true for classes in my view.
  • Enums just being named numbers. Again, I’ve blogged about this before, but it’s worth mentioning again. It’s possible to work around the lack of this feature (as the blog post readers pointed out!) but framework and language support would have been very welcome.
  • The “x” character escape sequence. Fortunately it’s rarely used, but it’s so error-prone. Quick, how different are “x8Good compiler”, “x8Bad compiler”? What’s the first character in each string? (This will appear soon on my brainteasers page).
  • The switch statement. There are lots of ways in which this could have been better designed. VB addresses some of them (such as making it easier to express multiple matching values) but there are other ways in which this construct needed overhauling. Fallthrough is (rightly) prohibited, so why not just force braces round the code in the case block instead of requiring a break statement? Aside from anything else, that would fix the somewhat bizarre scoping rules.
  • Wacky overload resolution. I entirely understand the point that introducing new methods in a base type shouldn’t change the behaviour in derived types – but if you’ve explicitly chosen to override that method, that should be more easily callable than it is. (See the first example of the brainteasers page to see what I’m talking about.)
  • The “lock” keyword, and associated issues. Basically, the IDisposable pattern should have been used for locking, and not every object should have a monitor associated with it. Developers should keep a close eye on what’s being locked, and being able to lock on everything takes away from this. Likewise “lock” creates a keyword for little purpose (and one which would otherwise be useful as a variable name etc).

Mistakes in C# 2

  • Lack of partial methods. I’m really only saying this because it broke the format of C# in Depth slightly. I’ve introduced partial methods along with partial types because they logically fit in with them, and they don’t fit in with any of the other features of C# 3 particularly. This is just a matter of not working out all of how partial types would be used – or at least not doing so early enough. (For all I know partial methods were on the table before C# 2 shipped – I wouldn’t be surprised.)
  • Possibly the lack of generic variance. This is certainly a big issue of understanding which is often raised as a question. On the other hand, I suspect that if/when it becomes available, it will raise just as many questions in terms of the detail anyway…
  • The System.Nullable class. It’s really only there as an historical accident, and I know it’s not a C# issue as such – but even so… (Note for extra clarity – I’m fine with nullable types and the System.Nullable<T> struct. It’s just the supporting class that I don’t like.)
  • InternalsVisibleTo requiring the whole public key for strongly signed assemblies instead of the public key token (contrary to the documentation). Ick.

Mistakes in C# 3

  • It’s a real shame that readonly automatic properties aren’t in C# 3. I suspect they’ll come in C# 4 (and they’ll be on my wishlist in future posts) but I think it’s reasonable to wonder why they weren’t included in C# 3. Immutability is a known pattern of goodness, and although C# 4 may well contain any number of more significant improvements towards making it easier, readonly automatic properties would have been a good start.
  • The way that extension methods are found. This issue was raised time and time again before release, and I’ve never heard a good defence of finding them by whole namespace, instead of allowing developers to say “use the extension methods found in this class, please”. As it is, anyone writing their own extension methods is likely to end up with whole namespaces devoted to a single type. It’s very odd.

Of course that’s not to say there aren’t other things I’d like to see – but these are more “features which were slightly misdesigned” rather than “features which I really want”.

I’m not trying to take anything away from the language designers – C# is still easily my favourite language in terms of its design, particularly in C# 3, but nobody’s perfect :)

Next time I’ll start giving my opinions of features that other people are calling for.

16 thoughts on “C# 4, part 1: Looking back at the past”

  1. Hey Jon, very nice blog entry.

    I’ll really be looking forward to some of the wish list items you would like to see in C# 4.

    The perspective you bring, with your strong background in Java, is very nice – there aren’t too many people who know both at a Deep level.

    Most people seem to be VB6 -> .Net, or C++ -> .Net. Very few seem to come from the Java world.

    Like

  2. Some of my personal gripes about the language, although they’re really more .Net gripes:

    – The weird “syncroot” element on the non-generic collections.

    – The equally weird “readonly” versions of collections (both generic and non). Especially as they’re not read-only.

    – The lack of support around proper usage for the IDisposable pattern. It’s very confusing, especially when tied in with the Finalizer infrastructure.

    – Lack of constructor inheritance. I’m sure there are many good reasons for this, but I find it very frustrating.

    – Lack of ability to specify CTOR rules in Interfaces. Again, probably good reasons, but I wish it was there.

    – Lack of ability to define static contracts.

    – Lack of basic method precondition contracts. e.g. the ability to declare “string@ x” to mean “don’t accept a null string as an argument”. Or equally, an attribute on the method: [NonNullableArgument firstName]

    – Inconsistent use of Format Strings across methods that should have them.


    Chris Mullins

    Like

  3. Sure. System.Nullable is a class with a few “support” methods for nullable types.

    System.Nullable on the other hand, is the struct which is the basis of nullable types.

    The features of System.Nullable could easily have been provided elsewhere – it just means that there’s a pointless “overloading by number of generic type parameters” which confuses matters.

    Sorry to not be clearer – although it kinda illustrates my point :)

    (Having said that, I mistakenly wrote “the System.Nullable struct” when I meant “the System.Nullable class” which was entirely my fault rather than the .NET designers’. I’m going to fix that in a tick.)

    Jon

    Like

  4. I really like C# design, but just to ‘add some value’:

    An event is just a delegate property with add and remove methods. Why there’s a event keyword but not a property one. Why automatic properties looks different to events ?(automatic events by default). I can understand some of the reasons (implementing add and remove is nos very frequently, and events are hard to understand so maybe is better to have a keyword to clarify) but it looks inconsistent to me.

    Like

  5. Chris — the ReadOnly properties of the old non-generic collection are extremely useful! They are hardly “weird”, as they work exactly the same as get-only properties — a read-only view on data that can be changed by someone else. In my own utility library, I’ve added similar ReadOnly views to all generic collections.

    SyncRoot is required to support ReadOnly views. There are two views (which are different object references) on the same collection, so you need some common object everyone you can put a lock on. That’s the SyncRoot.

    Now the old Synchronized property of non-generic collections, that was truly some weird stuff. I put it in the same bucket as the “lock” keyword — the MS people being over-enthusiastic about multithreaded programming before they had fully understood its implications.

    Completely agree with your other points, though — ctor inheritance, static contracts, and declarative argument restrictions are all features I’d like to see in C# 4.

    Like

  6. Jon, you can create readonly automatic properties in C# 3.

    For example:

    class Person {
    public Person(string name, string age) {
    this.Name = name;
    this.Age = age;
    }

    public string Name { get; private set; }
    public string Age { get; private set; }
    }

    Cheers,
    Justin

    Like

  7. Justin,

    That’s not a proper readonly property – it’s readonly from the outside but:

    1) The variable isn’t marked as initonly.
    2) You can accidentally set it from the rest of classs.

    I want a property which has the same semantics as a readonly variable – it can only be set in the constructor, and the JIT will know that.

    Jon

    Like

  8. In my mind the one big mistake was that generics was not in the first release of .NET.

    Read only properties would be interesting. I assume that the syntax would be something like:

    public readonly int Value { get; }

    And then Value can be set only within the ctor?

    Something else I would like to see for automatic properties is the ability to specify an attribute on the generated field:

    [field: NonSerialized]
    public string Name { get; set; }

    With the addition of tuples and lambdas I’d like to see ways to declare them more directly:

    class { string FirstName; string LastName} x = new { FirstName = “Jon”, LastName = “Skeet” };

    int(int,int) add = (x, y) => { x + y };

    What I’d really like to see in C# 4.0 are concurrent programming structures. I think the adaptation of the two “polyphonic” features from Cw would be excellent.

    Async methods, the method runs automatically on a background thread:

    public async MyMethod();

    Chords, which use async methods combined with normal methods to create a synchronized queued calling convention. The caller to the async method returns immediately, but callers to the normal method block until there is a corresponding call to the async method. The parameters of both the async method are available in the normal method:

    public async HasItem(string value);

    public string GetItem() & HasItem(string value) {
    return value;
    }

    Calls to GetItem() will block until there is a call to HasItem.

    Like

  9. Halo_Four – some of what you’ve suggested has already been covered elsewhere in the series.

    However, the async stuff in Cw I’m not so sure about. I think I’d rather have that in a library (like Ports) than in the language itself. I like to keep the language reasonably lean, and build things like this on top of it. This would be skewing the language to one particular way of doing concurrency, instead of different libraries providing different schemes all accessible within the core language.

    Like

  10. What I really like about C# 3.0 was that alot of specific language goodness was driven by trackling a large problem domain like LINQ.

    I know it wasn’t the only focus but it sure was a great way to focus the language features that made it into the language. It was especially cool in that all of the features benefit both LINQ and non-LINQ language users.

    Here’s hoping they focus on a few BIG problems like concurrency support or dynamic language support, I don’t care what, as long it is focussed and significant.

    Like

  11. Probably my biggest gripe is String escapes. With a double-quote enclosed string, you have to escape every special character. If you prepend with @, you only have to double up the double quotes and can have multiple lines. But if you paste in a block of XML, that often ends up with a lot of doubled-up quotes. I wish C# would take a page out of perls handbook and allow a generalized quote character. You start the string with a character that won’t be in the string (| pipe is often a good choice) and the string ends when you hit the next pipe. No hassles.

    Like

Leave a comment