Gotocph mads torgersen facebook

Why You Should Take Another Look at C#

Because you can and because you want to! You can because C# runs great on Mac, Linux, Android, and iOS (oh, and Windows); is targeted by your favorite editor; rests on a rock solid, time-tested industrial grade platform; and is open source. You want to because C# is an industry leader in language innovation, is your best option for native cross-platform mobile apps, and is toolable beyond compare. In this GOTO Copenhagen 2016 talk, Mads Torgersen invites you to play around in the key of C#, see why it’s not your uncle’s, and discover where the language is headed.


Download Slides

Introduction

My name is Mads Torgersen. I work on C# for Microsoft. I am getting old, I always carry a t-shirt with the name of the program and language I am working on in case I forget. I am here to talk about C#, and why it may be worth thinking about (even if you have not so far).

Stack Overflow runs a survey every year of their developers, and they ask them various questions (of course, it is skewed and unscientific in all ways). You have to be on Stack Overflow to participate.

C# is a widely used language (number four, and one of the three above is not a programming language–I’m not talking about JavaScript, I’m talking about SQL). C# is one of the main mainstream languages.

They also ask people whether they would like to continue using the language they are using, and they use that to rate the most loved technologies. C# is on this list as well. People love C#. There are some languages that they love more, but if you notice, many of them are languages with smaller audiences, very dedicated audiences that are maybe more part of a cult. It is only a few here at the bottom that are in both lists, that are both highly used and highly loved. It is nice to be one of the three technologies on that list, two of which are programming languages, and yay for Python also for being on there.

We constantly try to think about what is it that we are probably doing right, that we have still fairly enjoyed programming language after all these years. It seems to be not the fact that everybody uses C# because they have to, because people did 10 years ago at their company, and they have all this legacy code. There seems to be some energy around, and we want to try to keep that going. We have some ideas about why that may be, and that is what is driving our language evolution.

We are very eager to evolve C#. If you look at the language evolution scale (from a little to a lot), we tend to be aggressive about keeping the language fresh and modern. As the programming language state of the art evolves, do we. Sometimes we are the movers, sometimes we are the followers, but we try to keep the language a good choice for programmers in modern day. Not something you have to do because somebody made that choice in a previous decade.

I also want to point out F#, because it is our little sister language, and it is very popular, because it is also very small. F# is a much more functional language, and we benefit from the collaboration with F#, and the inspiration that it gives us in C# language design.

Changing the Tune - Why You Can Use C#

It has increasingly been the case that you can use C# elsewhere. We are pushing to make that an option. C# has been a massive, main programming language in Windows, but at the same time, we are complete newcomers to some other platforms. At least mostly so. It is this interesting situation, where now that it is becoming an option on all the platforms, we are at the same time very entrenched, and the fledgling language on some platforms. We are eager to help that adoption on those other platforms.

We have evolved our language technology. The compiler and IDE technologies that underlie the implementation of the language, called Project Roslyn, are enabling unique scenarios for programming in C#. One of the consequences is that work on the language core, and ripping it out of the Windows and Visual Studios specifics, means that it has become easy to implement C# in other IDEs. You can use C# in your favorite IDE, or your favorite editor.

We have moved from being a completely proprietary technology to being completely open source. Everyone can contribute to C#, and many people do. We are getting a conversation with the community that is vastly different now. It is more of a collaboration project, as opposed to, “Microsoft says…” That is very exciting. Rather than coming out every three years saying, “this is what we worked on, hope you like it,” we are now in a very open dialogue everyday with the community about our direction. We get feedback all the time - online, on GitHub, and elsewhere. We have much better quality on our design work as a result of it.

Let’s start with some of those other places that C# is.

C# Everywhere - Xamarin

Xamarin used to be a separate company. We acquired them six months ago. It is a technology for using C# to target, to make native apps for Android and iOS. It is technology based on letting you use the same language, and the same source code for the most part, to write apps for multiple different mobile platforms.

It works on iOS and Android. It targets Mac as well, and by the way, Windows too. It creates high-quality native UIs. A number of big apps are using this technology because it saves the effort of separate implementations on those platforms. It lets you use the language that you can use on the back end as well, which you can with Java, but it is not there yet with Swift or Objective-C. It is economy of scale, and it is a very good language for implementing apps.

Get more development news like this

It is based on the Mono project, an open source implementation done by people outside of Microsoft many years ago, and maintained ever since to target C# to other platforms and Windows. While we at Microsoft were tunnel-vision on Windows for many years, these people saw the cross platform potential of C# much before we did, and implemented this great cross platform implementation. Xamarin is based on that, and many of the apps that you see in the iOS or Android are stores that are based on C#. Either because of Xamarin, or because of Unity, which is probably the industry leading game engine.

C# Everywhere - Unity

Unity is based on Mono, and this 2D, 3D game engine is one that you target with C#. Many games are written in C#.

C# Everywhere - .NET Core

At Microsoft, we are working on .NET Core, which is a fresh implementation of the whole .NET stack, the runtime, and the libraries, that is intended to be lightweight, and for server-side use, for Cloud, and server workloads. It is cross-platform, works in Linux, Mac, and Windows. We are putting the ASP.NET framework on top, which is a broadly used web framework that you can now run on non-Windows machines, and it is open source. Why are we building a separate one? This helps with the lighter weight things that you want to do when you are on the server-side.

First, there is no UI framework, but it is able to do stand-alone deployment. For instance, you can ship the runtime together with your code; you do not have dependencies on various things being installed on the box that it happens to run on, in the cloud somewhere. It has a better architecture, makes it more suitable for microservices. It is trying to modernize our platform for the server-side as well. This proliferation of all these different .NETs that run on different platforms, or sets of platforms, creates confusion, especially if you are a library provider. You want to try to write something that runs on multiple different platforms.

We also do one called .NET Standard, which we are specifying, instead of APIs that are supposed to be an all-compliant .NET platform. If you target that, you could say target .NET Standard in your tool, and it will run everywhere. You claw back the ability to write code that works everywhere in the .NET ecosystem. We will evolve the Standard overtime, including new, core essential libraries, and you can then target whichever Standard you want. That is much the rub on where C# runs. Hopefully that should convince people that there is a much bigger addressable space for C# than there has traditionally been. It is exciting for us to be able to target that.

Roslyn - The C# language engine

I want to go to the more geekery side, and talk about Project Roslyn.

We modernized the C# language engine. It used to be that there was a C# compiler. It was written in C++, and then there was Visual Studio, and some language integration for C#. Both understood C# in their own way, a bit of code sharing, and nobody else could get in on the deal. If somebody wanted to understand anything about C#, write a tool, or add their own IDE support or whatever, they were lost. They had to start from scratch, because it was all black box. That was unsatisfactory for us as well.

When we decided it was time to rewrite the compiler, not only did we do it in C#, but we took some strong architectural stands on how it should be done. There should only need to be one place in the world where the C# semantics are implemented. We should build the thing that everybody can use for everything they want to do with the language. Regardless of platform, of what it is they are doing, whether it is a batch process, like a compilation, or whether it is an interactive situation like an IDE, full of erroneous code. It should work for all of those things. It is a lofty goal, and it took us quite a while, and many people worked on it. But we now have the Roslyn API, which does satisfy this goal.

Most things out there that understand C# are shifting over to Roslyn. Not all of them. The speaker in the room, Ted Brangs, is an exception to this for technical reasons of their own. The idea is that this is the code base that you use to implement IDEs and editors. If you have analysis tools of various kinds, linters that call out problems with your code. If you want to manipulate code, i.e., have automatic fixers or refactorings that produce new code from old code, you can use it. If you generate source, you can use it. If you are doing more interactive things, scripting or REPLs (like we have now a C# REPL in the Visual Studio), it is built on top of Roslyn. It still does compile the code and produce output.

This is a sampling of the things that you can do, and that people are doing in spades with Roslyn. This can be an explosion of language based tools, because people can now get off the ground much faster. It democratizes working with the language. You already have something you can ask about, the syntax and semantics, you need to add the specific bits to what you want to do. One particular community project that makes great use of this is OmniSharp.

OmniSharp - edit C# everywhere

OmniSharp is a project to make C# available on your favorite editor. The way they do it is clever: because C# now runs everywhere, they can take the Roslyn C# engine, and run it in a separate process on whatever machine you are developing on (a Mac, for example). They run that as a separate process and then they only need to do a thin integration into whatever integration layer that particular editor has that talks on the wire, using some wire format, talks to the process about everything regarding the language.

Every time you press a key, i.e., you press dot, and you want to get completion, it asks the process next door, “they pressed dot. What should I show in the completion list?” It knows all the semantics. It will tell them, “these five methods are available, show those”.

This separation of concerns, where all the language understanding is wrapped up in a separate process, can be created over that standardized wire format. That made it possible to go and implement good, semantically-aware C# modes in many editors (that some of you might love it, or hate).

I should note that Microsoft’s Visual Studio code, for instance, uses OmniSharp for its C# mode, which is an extension that you load in anything else. It is not built into the editor. C# is an extension like other languages.

Demo - Roslyn Analyzer

Let’s do probably the geekiest example. We have some resolution issues. To help people get started thinking about language-based tool, and to democratize, we created this framework, called the Analyzer framework, where it is easy to build something that analyzes people’s source code, and can give diagnostics on it. To build something, when you get those diagnostics, it will offer up fixes to the code.

If you think about:

  • your organization having special code styles that you want to enforce, or
  • you have refactorings that you want to build because you often do this manipulation of the code yourself, or you want to share that with the world, or
  • you have fixes that you often find yourself doing that you might as well automate… this is the tool for you.

This is a project type that you can install in Visual Studio and start using. When you open the project, it comes with boilerplate already built for you. Specifically, when you enter debug mode on a project like this, it takes that analyzer that you were writing, and the code fixes, and it installs them. They can be run in batch code, you can ship them as a Nougat package. It installs them as a Visual Studio extension, in a nested version of Visual Studio that it then runs as part of the debug mode. I have Visual Studio running Visual Studio with a code fixes that I am writing operative in the nested version of Visual Studio.

Let’s open some code in the nested version of Visual Studio. I have not completely written those analyzers yet. Here is some sample code that we want to operate on. The thing I want to implement is fairly syntactical, for simplicity, but I could have implemented various semantic rules as well. The Roslyn engine provides complete information for me to use, but it is bad style to have statements inside of if statements or else clauses that do not have curlies around them.

We want to implement that old-fashioned, rigid style of there always have to be curlies, because then you do not get many bugs as you edit the code later. We want to complain about this code in those cases, and for the sake of time, I will only implement it for if, but we could implement it for else. Let’s implement a little code analyzer live here.

I am not going to stop the nested thing. I am going to put a break point. What I did ahead of time is I am registering that, whenever we see an if statement, we should call this method AnalyzeNode. Whenever the source analysis in Visual Studio hits an if statement, go here. Let’s then go and trigger that. If we go to the nested Visual Studio here, and I do an edit, it will reanalyze the code, and it will hit the break point. I now get all information about where I am in the code that I can start working on. The thing that I get passed is a context object.

Let’s look what is inside of that context. I am able to report diagnostics if I do not like this if statement. I can get the node of the syntax tree that I am looking at, which is the if statement hopefully. Let’s start getting that out and if we hover over it, since we are in debug mode, that is an actual object that passed in. We see that it is indeed an if statement. Let’s get it as an if statement using essentially Roslyn as an object model for code.

I am looking at a syntax tree node, and it happens to be of the derived class that is an IfStatementSyntax. We can say var ifStatement is that thing. And now that is the only thing we are going to get called with, I am going to skip checking that it was an if statement. An if statement is wrong if the thing that is inside of it is not something with curlies around it. That is called a block. If this thing is not a block, SyntaxKind.Block, then I want to complain. I want to say to the user, “you are wrong.” Now I am going to report a diagnostic. I do not have that yet, I am going to use a little refactoring to generate a local for it.

I can create a diagnostic by saying Diagnostic.Create, and it takes a few things I happen to have prepared. A descriptor, is called Rule, and then I need some location. That is where to put a squiggle in the code when this problem appears. Then I need to say what kind of thing I’m looking at. We need to find out what the location is. Let’s do that refactoring again, generate a local. This is all while I am in debug mode.

What is the location? The node that I am looking at, the if statement. Where do we want the squiggle? Let’s have it on the if keyword. The if statement has an if keyword, because this is a concrete syntax tree. It has all the details about the code, including where everything is. And let’s get the location of that. Let’s see there is a GetLocation method. Let’s get the location of that if keyword and put that in. I wrote some code. Let’s remove the break point, and keep running in the debugger. We wait a little to see what happens, and now you see squiggles appear in the if statements.

That was all I had to do: write three, four lines of code in order to identify the problem, and tell the framework where to show it. To prove to you that it works, I can go and put curlies there and the squiggle will go away in that half.

It gets a little harder when you start to do complex things, but a relatively easy to use model of the language, including its full syntax and binding semantics, and people can build tools, share them out, and the whole editing experience for everyone using C#, regardless of which editor they use, as long as it is based on Roslyn, and regardless of which platform they are on, they can benefit from these.

The analyzer that I wrote can be equally run in batch mode. It could be part of the compilation process and it could flag warnings or errors, like the compiler does and its own native things. I could implement the fixer (but I am not going to do that in the interest of time) that fixes up the code and puts those curlies in.

That is the geek-out on the Roslyn side, and how that hopefully helps people get a better editing experience, a better development experience with C#, outside the language. It gave us a much better code base, a much better architecture code base, and obviously one in C#, we can dogfood our own language, that helps us evolve the language itself.

Evolution of C#

It is a lot easier for us now to evolve the language, and for the community to participate in that evolution through contributions. Many versions (I am not going to go through all of the version) - it shows aggressiveness that we have had in innovation.

I want to point out the Async. We did the LINQ, the queries that we introduced in C# 3. We take concepts that exist in interesting languages that are not very used, and we try to mainstream them, pull them into C# as a mainstream language, and help bring them to a broader market. The LINQ queries in C# are an example of comprehensions that you find in functional languages.

We pulled those in along with Lambdas. Now every language in the world has Lambdas. It was a little less common back then. Java had them now. Of course, way back in C# 2 we did Generics, only a little later than Java did. I was part of introducing Generics to Java, then went to C#, and was part of rolling it out there. In C# we did it right, in that Generics are deeply implemented into the runtime. Java took the more cautious approach of making Generics something that the compiler compiles away.

When you have Generics deep in the runtime, that is good for getting the semantic 100%, but it also means that the performance characteristics are very different, especially when you have value types in the language, like C# had from version 1, that Java is possibly getting it sometime in the future. When you have value types, you want Generics to recognize those and specialize for those value types you do not get much boxing and allocation around using Generics. It has to be that Generics makes your code faster, not slower.

Generics has really been the work horse for many of the language features we’ve implemented since then. We were able to do queries right, because of Generics. Because the Generics were deeply implemented in the runtime, were available through reflection, as we did all weird code quoting, and translating C# to SQL. It was all based on the fact that the types would flow, and that would be available even at runtime.

We integrated dynamic-ness into a static type system by having a type for when things were dynamic, called Dynamic. Again, it uses Generics heavily under the hood to make that efficient, and to avoid a bunch of boxing. Async is deeply reliant on Generics. In C# 6, we had Roslyn, and it is no longer a big war to implement any given language feature. We have more agility, and now is the time to take all those little features that we never implemented, that we wanted to implement, to make development easier, nicer, lighter, and cleaner.

We did a swath of those in C# 6, which is the version of C# that is out there now. And then in C# 7, we are taking on some of the deeper features again, that we think that we borrow heavily from the functional world, and we think that we are essentially taking the next step, in terms of dealing with data that is not necessarily object-oriented. I think you are seeing us start as a very object-oriented language and lean towards a more functional style as a supplement to the object-oriented, and trying to integrate those as well as we can. It is a bit of an inspiration from Scala and what it’s doing on the JVM, trying to make functional and object-oriented work well together, but definitely with our roots in the imperative object-oriented world for our situation.

Demo: Async C# 7

I am going to skip the Async demo, since most of you probably know what that is about. Let’s talk about what is coming into C# 7.

Let’s start out with tuples. I have my whole program. I have some numbers. Since they are recognizable, but not everybody may know them by heart: we have binary literals now. It is a tiny feature. It is good for when you are teaching your kids to program, these are the bits that are underneath these numbers. I am going to make one more. We also have digit separators, like other languages do, you can put underbars wherever you want, and the numbers get easier to read.

I want to implement a method called Tally, that summarizes the numbers in an array, that sums them up and counts them. We will tally these numbers. Of course I do not have that method yet, let’s use the refactoring to generate it. This is a static method. It returns void. It probably should return something else. Should it return the sum or should it return the count? Both. You can only return one thing in C# today, but tomorrow you can return two things, or three, or four. You can actually have as big tuples as you want, but it is probably a bad idea.

Let’s return two ints. This is a tuple type. It says two ints, it should be easy to understand. Here is a tuple literal that we will return a dummy to get started. That consists of some values, with parentheses and commas, and that should not be too surprising as syntax for it. When I go up, I can take the result of the tally, and I can look at it, and it is a tuple.

How can I use a tuple? Let’s print something out. Interpolated strings. The sum is probably the first thing in there. Let’s see what a tuple has: an Item1 and an Item2. It is obvious what they are, we can use them. Not the best names in the world, but it works. Tuples in C# can optionally have names for the different elements. I give them names. And what does that mean?

When I get it back, it tells me what they are, a good operational comment. It also means that if I go here, and press dot, in addition to these, this is a preview; the final version should probably hide the bad names. We have the good names, because you can see sum is here and I can use that name instead. These are the real names of the underlying type, but the compiler knows to keep track of these other names and show those instead.

It is important that tuples have names in them, because who can remember whether it was first name, last name, or last name, first name? They need to come with that information, and it needs to be operational. You need to be able to get it.

Of course, you might prefer to immediately pick the tuple apart as you get it and deconstruct it, and you can do that too in C#. You can say sum, count here, and now the tuple immediately gets deconstructed into a sum variable and a count variable that get declared. And instead of using the t. prefix, we can just say sum and count.

Let’s go now and implement this method. Instead of returning a dummy, let’s return a result, and let’s make the result equal to that dummy value to start with. We want to foreach over the numbers; let’s call them values. Then we want to update the result every time around.

Result is too long. I want to call it r. Let’s say r equals, and then a new tuple literal. I want to get the old value out. I wish r had names as well. Let’s go and give it names. You can give names in the tuple literal. You do that with the same syntax that you use for named arguments. Now r has an “s” and a “c.” We can say r.s, the sum that is already there, plus the new value v, and the count that was already there, r.c, plus one.

You might be justified in wondering, is not this terribly wasteful? Isn’t he allocating a new array? Or a new tuple every time around in this loop, and in these resource constrained devices, and cycles that cost money on the cloud? Isn’t it wasteful to allocate all these tuples?

It is not wasteful because the tuples are not objects. Tuples are implemented as a value type, as a struct in C#. They are not allocated. This is in place, updating some stuff that is already on the stack. Their value types are passed by copy, not by reference. Tuples do not have identity, they have values (which I think is the way tuples should be). They should be ephemeral. They should not have this life of their own, and it is more efficient.

Tuples are not only value types, they are also mutable. I know there are people in the functional camp that are going to revolt about this, but tuples are mutable. You can mutate a tuple. Instead of doing this, I could write r.s += value. And as a separate statement: r.c++, no pun intended. I can mutate the tuple in place, because that is not dangerous, because there is no shared mutable state among threads, because it is a struct? Nobody is sharing it. You pass it to someone, it is a copy, it is not dangerous.

Why does it always have to be object-oriented? Why does everything have to be encapsulated? Tuples do not have properties, they have fields. They are a struct with some mutable public fields. As simple as it gets, so you understand what you have. That is right for tuples, because they are not an abstraction; they are not wrapping something - they are values.

The remaining few things there are to say about tuples is that, since it is a type, it has value equality. You can use it as a key in a dictionary, for instance. If you want to be keyed off of two things, they both have to be right, then you can the tuple as the key, and everything works right; the hash code and everything work out right in the data structures.

Of course, it is a good way to get multiple results back from an asynchronous method, because if you’re async, and you return Task of the tuple, then it all works out when you go up here and await it. The tuple comes back out, and you can deconstruct and keep going. They are a good transport. The situation around multiple results was even worse for Async methods and other methods, because you could not use out parameters, but now you can use tuples.

Future: More With Patterns

We are starting to add pattern matching to C#.

if (o is Point(5, var y)) { WriteLine($"Y: {y}"); } // recursive patterns

state = match (state, request) // match expressions, match on tuples
{
    (Closed, Open) => Opened,
    (Closed, Lock) => Locked,
    (Opened, Close) => Closed,
    (Locked, Unlock) => Closed,
};

That is a whole new concept we are bringing in from the functional camp, and we are doing it gradually. You will see more on that front in later versions of C#, but we are taking a big step, in introducing the first couple of patterns.

Let’s turn this example into one where we have recursive lists of numbers. Instead of an int array, this is an object array, where we have a convention that the things inside are either ints or they are other arrays with ints in them; new object array, with some of these ints nested inside. Maybe there is also a null in there for good measure, and now we want to update the Tally method that it can deal with that.

Let’s take object arrays instead, and now we get an error because v is not an int anymore; it is an object. We need to know that it is an int before we can add it. We need some logic; in the old days, we would do a type test. If v is int, then we can go and do this; but, even though we checked that it is int, we do not actually know it again down here. We have to check it again and cast it.

Instead now, first approximation, you could think of it as extending the is expression. You can now declare a variable. When you ask if it is int, if it is, take that int and put it into the new variable i. Then the variable i has the value of v, but typed as int. Now I can add it here, and I know I’m good.

The is expression is now being extended to allow patterns, which is a new concept in C#. Patterns, instead of types. And patterns can be many different things. They cannot be very many different things now. They can essentially be constants, or type patterns. A constant could for instance be, v is 7 (that is now allowed because that is a constant pattern). We are taking these patterns, we are integrating them into language features, such as the is expression.

The other place where we are integrating it, to stay with the example, we are integrating into the switch statement. I can now switch on anything. It used to be that switch could switch on primitive types. It is this dinosaur of a feature, but now it can switch on anything. I can switch an object: switch on v. In my switch statement, I can have cases that have not constants in them, which are now a special pattern, but the cases can have any pattern. I can say case int i. (I have to remember the break, that is why I am getting the squiggly.)

I have used a pattern. I extended the case clauses in the switch statement to be able to apply a pattern and say, “when this pattern applies, do this particular case.” I can modernize the switch statement. I can say case object array, which is the other thing I am expecting. Let’s call that a, and I can put conditions in my switch, in my case clauses. I can say, “I only want the object a when a is longer than zero, because a.Length is greater than zero (otherwise there is no work to do).” When that is the case, I can do var t = Tally, the nested array, and add that to r; r equals r., you know how it goes: r.s + t.sum, r.c + t.c. And a break. This is a generalization of existing features with patterns, and that is how far we went in C# with pattern matching.

There are more things we want to do with patterns in the future. We want to have smarter patterns. You should be able to have recursive patterns. We let you specify in a given type that it can be deconstructed. So you can specify in a Point type, for instance, that it can be deconstructed, like a deconstructed tuple into separate variables. When things are deconstructable, we put that together with the pattern matching, and allow you to, if both check that o is a point, and if it is, deconstruct it, and maybe apply patterns recursively: if o is a point, and the first part of that point. The x is 5, then put the second part into variable y, and do something with y. You can get smarter patterns. You can probably also write unreadable code with this, but in general it is going to be useful to be able to dig little deeper in the pattern.

We should come up with new places to have patterns. The switch statement, it’s from the 1960s. And maybe there is an expression version of the switch statement. Maybe it’s a match expression, as it is called in functional languages, that has a niftier syntax, it is expression based, the cases are expressions, and your code gets more terse. But now we have the notion of patterns, we can both add new patterns, and add new places where they occur. That is one thing that we are focused on for the next version of C#, which we are already working on, because C# 7 is pretty much done. (We have not shipped it yet, and do not ask me when.)

Future: Nullable Reference Types

string? n; // Nullable reference type
string  s; // Non-nullable reference type

n = null;  // Sure; it's nullable
s = null;  // Warning! Shouldn’t be null!
s = n;     // Warning! Really!

WriteLine(s.Length); // Sure; it’s not null
WriteLine(n.Length); // Warning! Could be null!

if (n != null) { WriteLine(n.Length); } // Sure; you checked
WriteLine(n!.Length); // Ok, if you insist!

One of the things that is becoming mainstream in newer lovely little languages is the ability to distinguish in the type system, when things are supposed to be nullable and when they are not.

This variable is supposed to sometimes be null, it is part of its domain; this one is not, why am I getting reference exceptions all the time? Swift has that as well. Can we do something for C# along these lines, even though we have had 7 versions now, where nullability has been purely a runtime thing?

We think we can: we already have that trailing question mark in C# for nullable value types. If we allow you to apply that to a reference type, maybe that is how you say that something is nullable. If you say that, there are things we will not let you do. On the other hand, if you do not say that, and you are up into this new world somehow, we will expect the thing in there to not be null.

We will help you maintain that, meaning I can assign null into the n, but not into the s. And I cannot assign n to s without any qualification either, because that might be null. I am protecting the variable from the variables that it is not supposed to hold. On the other hand, when I want to use it to reference it, I can do s.Length without any qualification, because I know it is not null. I know it is probably not null, because we cannot give any absolute guarantees in a language like C#, but it is probably going to find most of the places where you are not supposed to dot.

n.Length is going to warn you about it potentially being null, and you potentially getting that null reference exception. The way to get around that is, some of these new languages have specific new null-checking features. They have a new way that pattern matching (or whatever you can use to check for null). We do not want to change how you check for null. There are already 7 ways of checking for null in C#. Instead, we want to have the compiler track when you checked that something was null, then use that knowledge.

If you have an if statement that sees that n is not in fact null in this case, then we will know that in the scope of that check. It is, in fact, not null, and we will assume that it is fine that you dot into it. Are there ways to get around this? Yes, but you have to work to get around it now. Instead, you have to work all the time to eliminate all your null reference exceptions.

There will also be a “Dammit” operator, where you can walk up to a nullable thing put a postfix bang (!) on it, and that means assuming in the type system that was not null because I know better than the compiler. Sometimes you tested something else and you knew somewhere; in this case, this is never null, and if you are bold enough to stick with that, you get to insist, and we will let you dot without a warning. We are already working on this feature, and we are hoping to get it in the next generation of C#.

Hopefully that is going to be useful. The interesting thing about a feature like this is that it needs to not only go into the language, but we need to make sure that our frameworks are adequately annotated, that when you build on those, you get the right null abilities propagated into your own code. It is a challenging feature, but I think it is worth it.

Next Up: Announcing Realm .NET!

General link arrow white

About the content

This talk was delivered live in October 2016 at goto; Copenhagen. The video was transcribed by Realm and is published here with the permission of the conference organizers.

Mads Torgersen

Mads is the language PM for C# at Microsoft, where he runs the C# language design process and maintains the language specification. He is also on the design team for TypeScript and Visual Basic, and he contributes to the Roslyn project, which has reinvented the C# and VB compilers and taken them open source.

4 design patterns for a RESTless mobile integration »

close