C# 7.0 and Beyond with Mads Torgersen

New Zealand and Wellington especially are not exactly big so when the program manager of C# language comes into town for a meetup it would be a shame to stay at home.

This Wednesday the amazing WelliDotNet meetup hosted Mads Torgersen; a guy responsible for the C# language design (and TypeScript and Visual Basic in the past); and he talked about the new features of C# 7.0 and where the next versions are heading.

Mads started with the results of Stack Overflow Developer Survey 2017 results where C# is 4th most used programming language.

Both C# and TypeScript are in the top 10 used programming languages

And it also made it to the top 10 most loved programming languages.

As well with TypeScript on impressive 3rd place

He thinks the reasons behind that are

  • C# now runs on every platform (not just Windows),
  • Roslyn is an open compiler,
  • you can use your favourite editor, not just Visual Studio and
  • everything is open source.
Q: How hard was it to get more open?
A: It was hard initially and was happening more on team level. Now it aligns with the overall vision of Microsoft and how products interact with each other (e.g. Azure).

C# evolution is a balancing act as you want to

  • aggressively improve and also stay simple,
  • improve existing development and become attractive to more users,
  • embrace new paradigms but stay true to the spirit of C#.

New features in C# 7.0

Mads started with minor features and talked briefly about new binary literals. And the _ separator.

int[] x = [0b1, 0b10, 0b100, 0b1_000];
int y = 1_000_000;
Q: How does C# 7.0 relates to the CLR? Does it need an updated runtime?
A: You can target CLR 2.0 — no new feature is implemented with new IL instructions.

Tuples

One of the major features is the direct support of tuples — System.ValueTuple. So now you can write functions with multiple return values.

private static (int, int) Tally(int[] numbers)
Q: How is System.ValueTuple different from System.Tuple?
A: It is a struct as opposed to System.Tuple being class. And it has just 7 fields and the rest becomes a tuple (e.g. Item8 is a tuple).
Q: Why is System.Tuple class?
A: It was a design decision from F# team — but they might regret it as well.

Also, you can write tuple literals like(0, 0);

Q: Is that limited to value types only?
A: No, they are generic types underneath.

You can optionally provide names for tuple items in method definitions, literals and everywhere else you use tuples.

public static (int sum, int count) …
var x = (sum: 0, count: 0);

These names are tracked only by the compiler; in runtime they are not used and only Item1 style is visible. In debugging the names are available but not if you use reflection.

Another feature is deconstruction of tuples with _ notation for unused variables — discards.

(int sum, _ ) = Tally(numbers);

The deconstruction could be also used with your own types overriding the deconstructor.

Tuples are mutable but it is discouraged to mutate them — items are public fields which mitigates every downsides though. You get equality, hashcode computation and all the benefits of using structs out of the box.

Local functions

Apart tuples you can write local functions — function inside a function. It could improve readability of your code while keeping it closed and nicely contained.

private void MyFunction()
{
Add(0, 1);
void Add(int s, int c => r = (….);
}
Q: Can you pass local function as a lambda delegate to other function?
A: Yes, you can.

Pattern matching

C# finally gets pattern matching in a slightly awkward syntax.

switch (v)
{
case int i:
Add(i);
break;
case object[] a when a.length > 0:
...
}
Q: Is there a plan for better matching syntax?
A: Yes, it is on the agenda.

Note that you can use any condition expressions and it’s capable of extracting the value matched to the “local” variable. With that feature switch is now case sensitive.

Q: Is this a breaking change?
A: No, because the previous switch expressions were using constants which didn’t care about the order.

Others

And with that a few other smaller features. You can declare variable in the middle of expression.

int.TryParse(…, out var x) { x += 1; }

And you can do ref returns and ref locals. Which is useful for low level development where you don’t want to allocate objects and want to avoid garbage collection.

The future

New versions of C# are planned to be released on quarterly basis which sounds quite daring. The next proposals are just drafts and could be changed in the future.

C# 7.1

This should be a release of minor convenience features that are not really related to each other, are small and self-contained.

Being able to define async Main function even if it is mostly for demonstration purposes.

And explicitly state default initialisation with

int i = default

enhance the null inference

int? n = b ? i : null

add tuple projection initialisers

var t = (i, n); return t.i;

and add discards to more places

o.PropertyChanged(_, _) => …

C# 7.2

This release will focus on more low level stuff without the need to work with pointers. There is a lot of game developers using C# with Unity and better performance could also be used in finance and other applications.

Those features could include ref readonly parameters and returns (the opposite of out parameter which needs to be assigned) — it says don’t modify me.

The extension methods are not ideal so redesign them and allow them to be used with refs and on structs.

And allow ref conditionals.

Another feature could include readonly structs that don’t need to be copied and a new ref-like structures for abstraction over a chunk of memory.

C# 7.3

This version should focus on nicer patterns and developer’s user experience. That could involve better recursive patterns, nicer syntax for pattern matching and tuple patterns.

C# 8.0

Major release in which the C# team might introduce changes to CLR — that would be for the first time since the introduction of generics. All the features added since were mostly compiler tricks.

One proposed feature are nullable reference types.

string? n; // nullable — enforces checking before usage
string s; // non-nullable
n = null; // sure
s = null; // warning
s = n; // warning
s.Length(); // sure
n.Length(); // warning
if (n != null) { n.length } // sure
n!.length // sure – a new operator converts into non-nullable

Big feature could be adding default implementation to interface members. One of the use cases would be making C# a great tool for working with mobile platforms (both Java and Objective-C supports this feature) and make Xamarin even more awesome.

And lastly a few improvements around async with async streams and disposables and adding foreach await to process data when coming and using await for safe application of disposable pattern.

C# could add records (similar to Ruby’s OpenStruct) for simple classes with default implementation of deconstruction, hash codes and equality.

class Person(string name, string lastName);

Lastly, there might be a support for immutable objects.

Conclusion

So that’s it. The future for C# is pretty bright and the features are exciting. I’m quite happy about pattern matching introduction and deconstruction. And maybe in the future immutable objects with some nullable reference types. That’d be cool.

Again, big shoutout to WelliDotNet not just for the pizza but for the great event with the world class speaker.


If you liked this article you might enjoy C# Digest newsletter with 5 links from the .NET community that I put together every week.