//Build Changes Everything
I started this series after giving a presentation at NDC London on the potential features up for discussion in C# 7. That information was based on the public design discussions on GitHub. Now that //build
has happened, we know a bit more about the plans. There is even a public preview of Visual Studio 15 available for download. There are two versions: a ‘classic’ installer, and a new lightweight installer that runs much more quickly but has fewer scenarios supported.
I have installed both installers of Visual Studio 15 on my machine. They install side-by-side, and my machine works well. (It is also a machine with Visual Studio 2015 on it, and that’s been unaffected. This is still pre-release software, and you should proceed with some caution.
All of which means that there are two important updates to this series: First, the plans have been updated. The team announced at //build that the languages will have a faster cadence than before. That’s great news. But, it comes at a price. Some of the features that were slated for C# 7 are likely to be pushed to the release that follows C# 7. Private Protected
is one of those features. Non-Nullable Reference Types (covered in my NDC talk, but not yet in this blog series) may be another.
Immutable Types and With Expressions
Now that those announcements are made, let’s discuss the addition of ‘with expressions’ to make it easier to work with immutable types.
Immutable types are becoming a more common part of our design toolkit. Immutable types make it easier to manage multi threaded code. Shared data does not create issues when that data can’t change.
However, working with immutable types can become very cumbersome. Making any change means making a new object, and initializing it with all the properties of the original object, except the one you want to change.
With
expressions are meant to address this issue. In their most basic use, consider that you have created an immutable Person
object:
var scott = new Person(“Scott”, “Hanselman”);
Later, you find you need an object that’s almost the same, but must have a different last name:
var coolerScott = scott with { LastName = “Hunter” };
This simple example shows the syntax, but doesn’t provide great motivation for using the feature. It’s almost as simple to create a new object and explicitly set the two fields by calling the constructor. With
expressions become much more useful in real world scenarios where more fields are needed to initialize the object. Imagine a more extensive Person
class that included employer, work address and so on. When a Person
accepts a new role, the code to create the new object becomes much more heavyweight. And it’s all boilerplate code. That represents a lot of busy work that adds minimal value. In those cases, With
expressions are your friend.
This feature will leverage a convention found throughout the Roslyn APIs. You may have seen that many types have .With()
methods that create a new object by copying an existing object and replacing one property. The proposed feature would use a With()
method if one was available. If not, one proposal would generate a call to a constructor and explicitly set all the properties. Another concept would only support types that had an appropriate With()
method.
The syntax for With
expressions was originally proposed for record types (which I will cover in a future blog post). Record types are a new feature, and the compiler can generate all the necessary code to support new syntax like With
expressions. The current proposal would specify that Record
types would generate With()
methods that would support this language feature.
When With
Expressions are applied to record types, the generated With()
method provides a great example of how such a method can be generated that would support many permutations of With
Expressions. That proposal minimizes the amount of work necessary to support a full set of With
Expressions for all combinations of updated properties.
Open Questions
In the previous section, I said that one proposal would fall back to a constructor if a With()
method was not available. The advantage to that design is that With
Expressions would work with all existing types. The advantage of requiring a With()
method is that it enables richer support for positional and name mapping.
But there are more questions. In the scenario above, suppose the Person
type was a base class for other types: Teacher
, Student
, Teaching Assistant
, Tutor
, Advisor
. Should a With
Expression that uses a variable of type ‘Person
’ work correctly on any derived type? There’s a goal to enable those scenarios. You can read about the current thinking in the February C# Design Notes.
With
Expressions are one language feature that will make working with immutable types more pleasant and natural in C#. These features will make it easier to create the designs we want to support. It’s part of that “Pit of Success” design goal for C#: Make it easier to do the proper design.
Most importantly, these issues are still being discussed and debated. If you have ideas, visit the links I’ve put in place above. Participate and add your thoughts.
Focus
- Issues with current design
- Performance relating to runtime analysis