Tag Archives: C# 7

Last time on this blog I talked about the new tuple feature of C# 7. In Visual Studio 15 Preview 3, the feature wasn’t quite finished; it lacked 2 important aspects:

emitting metadata for the names of tuple elements, so that the names are preserved across assemblies

deconstruction of tuples into separate variables

Well, it looks like the C# language team has been busy during the last month, because both items are now implemented in VS 15 Preview 4, which was released today! They’ve also written nice startup guides about tuples and deconstruction.

Note that the intermediate variable t from the previous post has disappeared; we now assign the count and sum variables directly from the method result, which looks much nicer IMHO. There doesn’t seem to be a way to ignore part of the tuple (i.e. not assign it to a variable), hopefully it will come later.

An interesting aspect of deconstruction is that it’s not limited to tuples; any type can be deconstructed, as long as it has a Deconstruct method with the appropriate out parameters:

The Deconstruct method can also be an extension method, which can be useful if you want to deconstruct a type that you don’t own. The old System.Tuple classes, for example, can be deconstructed using extension methods like this one:

They’re classes, i.e. reference types. This means they must be allocated on the heap, and garbage collected when they’re no longer used. For applications where performance is critical, it can be an issue. Also, the fact that they can be null is often not desirable.

The elements in the tuple don’t have names, or rather, they always have the same names (Item1,Item2, etc), which are not meaningful at all. The Tuple<T1, T2> type conveys no information about what the tuple actually represents, which makes it a poor choice in public APIs.

In C# 7, a new feature will be introduced to improve support for tuples: you will be able to declare tuples types “inline”, a little like anonymous types, except that they’re not limited to the current method. Using this new feature, the code above becomes much cleaner:

Note how the return type of the Tally method is declared, and how the result is used. This is much better! The tuple elements now have significant names, and the syntax is nicer too. The feature relies on a new ValueTuple<T1, T2> structure, which means it doesn’t involve a heap allocation.

You can try this feature right now in Visual Studio 15 Preview 3. However, the ValueTuple<T1, T2> type is not (yet) part of the .NET Framework; to get this example to work, you’ll need to reference the System.ValueTuple NuGet package.

Finally, one last remark about the names of tuple members: like many other language features, they’re just syntactic sugar. In the compiled code, the tuple members are only referred to as Item1 and Item2, not count and sum. The Tally method above actually returns a ValueTuple<int, double>, not a specially generated type. Note that the compiler that ships with VS 15 Preview 3 emits no metadata about the names of the tuple members. This part of the feature is not yet implemented, but should be included in the final version. This means that in the meantime, you can’t use tuples across assemblies (well, you can, but you will lose the member names and will have to use Item1 and Item2 to refer to the tuple members).

About two weeks ago, Microsoft released the first preview of the next version of Visual Studio. You can read about what’s new in the release notes. Some of the new features are really nice (for instance I love the new “lightweight installer”), but the most interesting for me is that it comes with a version of the compiler that includes a few of the features planned for C# 7. Let’s have a closer look at them!

Enabling the new features

The new features are not enabled by default. You can enable them individually with /feature: command line switches, but the easiest way is to enable them all by adding __DEMO__ and __DEMO_EXPERIMENTAL__ to the conditional compilation symbols (in Project properties, Build tab).

Local functions

Most functional languages allow you to declare functions in the body of other functions. It’s now possible to do the same in C# 7! The syntax for declaring a method inside another is pretty much what you would expect:

Here, the Fact method is local to the Factorial method (in case you’re wondering, it’s a tail-recursive implementation of the factorial — which doesn’t make much sense, since C# doesn’t support tail recursion, but it’s just an example).

Of course, it was already possible to simulate local functions with lambda expressions, but there were a few drawbacks:

it’s less readable, because you have to declare the delegate type explicitly

it’s slower, due to the overhead of creating a delegate instance, and calling the delegate vs. calling the method directly

writing recursive lambdas is a bit awkward

Local functions have the following benefits:

when a method is only used as a helper for another method, making it local makes the relation more obvious

like lambdas, local functions can capture local variables and parameters of their containing method

Ref returns and ref locals

Since the first version of C#, it has always been possible to pass parameters by reference, which is conceptually similar to passing a pointer to a variable in languages like C. Until now, this feature was limited to parameters, but in C# 7 it becomes possible to return values by reference, or to have local variables that refer to the location of another variable. Here’s an example:

On line 6, it looks like I’m assigning a value to the return of a method; what does this even mean? Well, the GetByRef method returns a field of the Foo class by reference (note the ref int return type of GetByRef). So, if I pass "x" as an argument, it returns the x field by reference. If I assign a value to that, it actually assigns a value to the x field.

On line 8, instead of just assigning a value directly to the field returned by GetByRef, I use a ref local variable y. The local variable now shares the same memory location as the foo.y field. So if I assign a value to it, it changes the value of foo.y.

It’s likely that most C# developers will never actually need this feature; it’s pretty low level, and not the kind of thing you typically need when writing line-of-business applications. However it’s very useful for code whose performance is critical: copying a large structure is expensive, so if we can return it by reference instead, it can be a non-negligible performance benefit.

Pattern matching

Pattern matching is a feature very common in functional languages. C# 7 introduces some aspects of pattern matching, in the form of extensions to the is operator. For instance, when testing the type of a variable, it lets you introduce a new variable after the type, so that this variable is assigned with the left-hand side operand of the is, but with the type specified as the right-hand side operand (it will be clearer with an example).

Typically, if you need to test that a value is of type DateTime, then do something with that DateTime, you need to test the type, then cast to that type:

It’s very similar to a switch, except that it’s an expression, not a statement.

There’s a lot more to pattern matching than what I mentioned here. You can look at the spec on Github for more details.

Binary literals and digit separators

These features were not explicitly mentioned in the VS Preview release notes, but I noticed they were included as well. They were initially planned for C# 6, but didn’t make it in the final release. They’re back in C# 7.

You can now write numeric literal in binary, in addition to decimal an hexadecimal:

int x = 0b11001010;

Very convenient to define bit masks!

To make large numbers more readable, you can also group digits by introducing separators. This can be used for decimal, hexadecimal or binary literals:

Conclusion

So, with Visual Studio “15” Preview, you can start experimenting with the new C# 7 features; don’t hesitate to share your feedback on Github! And keep in mind that it’s still pre-release software, lots of things can change before the final release.