Microsoft haven’t committed to anything in C# 4 yet. However, there have been hints about what they’ve been considering in Eric Lippert’s blog, and more than hints in Charlie Calvert’s blog. There’s not a lot to go on yet, but:
Most of Eric’s posts about immutability have so far been about immutable data structures. However, the first post in the series did mention that they’re playing around with immutability from the point of view of potential language support. Joe Duffy also wrote about immutability at roughly the same time.
What can we expect in terms of support? Possibilities:
- Compiler checking via attributes, as per Joe’s posts
- Immutable collections to make it easier to sensibly embed collections within immutable types
- Readonly automatic properties (as I mentioned in part 1 – I’ll expand on this in the next post)
I’m not sure what could be usefully added beyond those. One possibility, however: what about automatic equality and hashcode generation? I touched on this last time when talking about “instant data types” but I don’t see why it shouldn’t be applicable in general. After all:
- Immutable types are good candidates for dictionary keys – or to put it the other way round, using mutable types as dictionary keys is a risky idea
- If all immutable types automatically override GetHashCode and Equals, and immutable types can only compose other immutable types, everything should just work
- The obvious implementation of Equals and a “multiply, add, repeat” implementation of GetHashCode are pretty reasonable for many, many types. You could always manually override the methods if necessary.
One downside: Equality doesn’t really work well when there’s an inheritance hierarchy involved. Read Josh Bloch’s “Effective Java” for a detailed discussion. (Ooh, new edition coming out soon. Should make for great reading.)
Generic variance support
Once again, Eric has posted rather a lot on this, concentrating on two aspects: interfaces and delegates. I believe these are already supported in the CLR (I’m sure interfaces are, and I suspect delegates are too).
Just to be clear, I don’t think anyone should expect unsafe covariance/contravariance. The following code still won’t compile (at least unless things go very differently to how I expect):
IList<string> strings = new List<string>();
IList<object> objects = strings;
objects.Add(new object()); // Oww!
This code, however, would be okay, due to the “readonly” nature of iteration:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
That’s the interface side. For delegates, this would probably be possible:
Action<object> objectAction = (x => Console.WriteLine(x));
Action<string> stringAction = objectAction;
// Covariance of returns (and output parameters?) from delegates
Func<string> stringFunc = () => “foo”;
Func<object> objectFunc = stringFunc;
All of this is conceptually good. It’s more for people to understand, of course, but it’s still a useful thing to have available.
Dynamic calling support
This one really surprised me – to the extent that I’ll now need to edit the last chapter in the book so as not to look stupid when it’s published. (It’s fine to be wrong when predicting the future, but making a prediction which has already been proven false before publication is embarrassing.) I expected C# to stay fully static forever. However, it looks like the C# team is at least strongly considering making dynamic calling support available. Read the blog for more details, but note what isn’t included: C# reacting dynamically. In other words, Ayende’s beloved
IDynamicObject support isn’t being proposed (at the moment) – although I guess there’s always a possibility that the DLR support will somehow be available through “normal” C# without extra compiler support.
This will disappoint some people of course, but I’m happy enough. I can’t see myself using the new support particularly often, and I’m slightly worried at the extra complexity required in the language spec to explain what it will actually do, but I’m likely to treat it in roughly the same way as unsafe blocks – something to ignore most of the time.
As you can see, there’s not a lot really on the table yet. That in itself is quite interesting, however – as well as the nature of the changes. I believe that the changes from C# 3 to 4 will be much more like those from 1 to 2 than 2 to 3. Think about when VS 2005 was released – C# 3 extensions were already available in CTP form for the VS 2005 beta. Here we are with VS 2008 having RTM’d a while ago, and we only have a few ideas to mull over. Now, I’m sure that there are implementations of all of the above features and almost certainly more – but they’re not putting them out just yet. Hopefully we’ll learn more over the next few months.
The big difference with C# 3 was that there was a grand plan: LINQ. Almost every feature in C# 3 (basically not automatic properties or partial methods) supports LINQ in some way or other. I don’t see a big plan for C# 4. That’s a very good thing, in my view. We need time – quite a lot of time, I suspect – to digest LINQ. Awful as the phrase is, LINQ has the potential to be a paradigm shift in development. Those shouldn’t come along too often. Disparate changes can still be incredibly useful of course, so let’s not lack ambition for C# 4 – but I’m expecting idiomatic C# 4 to still be roughly similar to idiomatic C# 3, which certainly couldn’t be said of C# 3 to C# 2.
Only one more post in the immediate future: my own ideas for C# 4 (or at least those which I’ve come up with independently, even if others have mentioned them too).
10 thoughts on “C# 4, part 3: Ideas from Microsoft”
Yes, the CLR already supports delegate co/contravariance on generic delegates constructed with reference types. That makes this feature tremendously easy to implement in the language.
Though of course, implementation is a relatively small cost. This language feature makes the testing burden considerably heavier; that’s where the cost is.
Are we expecting any of this to cause .Net Framework 4.0 to require a new CLR?
Or is it expected that we will be good with v2.0?
I think the dynamic calling support will rely on the DLR – whether that will be part of .NET 4.0 or not I don’t know, nor what its precise relationship to the CLR is.
Basically I think it’s too early to tell for sure.
I’d be surprised if there wasn’t a new CLR in the next version.
I’m not too surprised of the dynamic calling support. But, based upon Eric’s blogging of late and the PFX, I would have though there would have been lots of energy into concurrency, immutability (which is important to concurrency) and co-/contra-variance. But, there’s been lots of work on the DLR and it’s only a matter of time before it makes its way into the mainstream.
Of the three you outline here, my priorities are variance and immutability. Dynamic call isn’t something I will use to any great extent in the foreseeable future.
How would you see immutability working with serialisation(both binary & xml) or do you belive it isn’t important?
Ollie: that’s a good question, and one which affects another of my wishlist questions. I would still want to be able to serialize/deserialize things and keep immutability – but I can see how it could be tricky.
It feels like serialization of immutable data structures *should* be easier in some senses – if you think of serialization as “freeze drying” objects, and think that immutable objects are already “frozen” in some senses, there ought to be a way the two ideas can link up nicely – but I’m not wise enough to know it.
I can’t say that serialization is something I use *that* frequently with whole immutable trees, but equally I can see it’s a big deal for many people! Definitely one for the language designers to mull over…
Immutability support sounds great. However, I disagree that overriding Equals and GetHashCode in a reference type is a good idea. In practice, there’s a danger in changing reference semantics to value semantics, regardless of whether a type is immutable or not (which also won’t be obvious unless IntelliSense plays the game too).
I.e., IMO, if you want to key a dictionary with a reference type, but you want to apply value-type semantics, encapsulate an implementation of IEqualityComparer; otherwise, just use an immutable value-type to begin with.
I don’t really see the “danger in changing reference semantics to value semantics”. Immutable reference types do indeed have value semantics in many (but not all) ways – I don’t see why that’s a bad thing.
Let’s use a concrete example: string. Do you believe that should be a value type rather than a reference type? Or that it shouldn’t override Equals/GetHashCode?
The danger isn’t in its implementation or behavior, it’s in ambiguity. I know how much you care about clarity (we agree that’s important :) and the problem with using a reference type as a value type is that it’s not obvious at all unless you examine the code.
String is an exception because we all know how it works. We expect it to function with value-type semantics, for obvious reasons. Though a Person class, for example, is not obviously a value type.
And doesn’t one class using a reference type, _knowing_ that it behaves like a value type, break encapsulation? Reference types do not, in the large majority of cases, behave like value types, so knowing that one does is knowing an implementation detail that shouldn’t be public (an actual value type can be used instead since its true semantics would then be public knowledge).
I guess the point is that it just increases the chances of having some strange bug that isn’t easily tracked down if you miss it while coding. (I’m thinking keying dictionaries, but I’m sure there’s other situations similar to the nuances of normal value types.)
Well, you wouldn’t need to examine the code if you document clearly that it’s immutable. That’s one of the benefits of putting it in the language/runtime, in fact – it could be *automatically* documented, so that just looking at the declaration (whether in code or XML docs) could tell you immediately that it’s an immutable type, and therefore has similar-to-value semantics.
I’ve never found it an issue, to be honest – I usually find it fairly obvious that something is meant to be immutable, when all the properties are read-only :) However, extra confirmation of that in an auto-generated and validated way would be welcome, IMO.