Did you know that C# has been around for 17 years? It started off as Microsoft’s response to Java, but now, in its “late-teen” years and seven revisions later, it is one powerful and popular language. Recently, C# has introduced more innovations in a short period of time than ever before. In general, all Microsoft technologies have an accelerated rate of innovations.
This is due to the fact that Microsoft has made a few new decisions that affected all its developer products and technologies. The first of them was to decouple releases of Visual Studio, .NET framework, and C#, giving them space to breathe and follow their own paths. Before, these technologies were shipped together, and that kind of slowed down the progress of each of them. This also affected the pace of releases, which has increased in the past few years.
The second change that Microsoft has introduced is that it is much more open to developers than it was in the previous period. By this, I mean that we can now follow Microsoft’s GitHub, and learn about new features, even though these features are only in the proposals state. That is how we can see some of the proposed features that will be available in new version of C#.
Don’t get me wrong, C# 8 is not scheduled anytime soon. After all, there is already work ongoing towards C# 7.2 and it looks like there are also plans for a C# 7.3. So, this revision is far down the road. Still, we can take a peek at some of the new shiny things that will be provided. Some of the features were already presented by Mads Torgersen in an interview on channel 9 and I am pretty excited about some of them. So, let’s check some of them out.
Nullable Reference Types
I think I read somewhere that 70% of all bugs in C# are directly correlated to the null reference exception, but don’t take my word for it, because at this moment I cannot find the reference or source of this statement. Still, I would not be surprised if that were true. Even the creator of null concept (first introduced in Algol W language in 1965), Tony Hoare, called it ‘billion-dollar mistake’ and publicly apologized for it. Still, it seems that now we are stuck with this concept and all its pitfalls.
C# has a history with null, too. Language has two large types of variables, primitive and reference, and only reference variables can have the null value. In fact, reference types have the null value as default. But, in C# 2.0 Microsoft introduced nullable versions of primitive types, which are denoted by a ‘?’ after type name. This means that ‘int?’ is basically an integer variable that can have the null value. As you can imagine, this allowed the null reference exception to hide in various sections of the code.
Thus far, the community used partial solutions like Code Contracts or third-party solutions, like Fody NullGuard, to forbid assignment of the null value to some variables, but language support for this problem is long overdue. It seems that C# 8 will change this by introducing the Null Reference Type. This feature will give developers options to define references which are non-nullable.
Per the design proposal, you would still be able to do something like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
String s = null; | |
Console.Write(s); |
Now, this code will generate a warning because String cannot have value null. Instead, this code should be used:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
String? s = null; | |
Console.Write(s); |
However, this will probably cause Write function to generate a warning because it should not accept nullable values. This cascade of warnings will help us detect stuff we are not doing in a properly.
Of course, this feature will be opt-in, so the legacy code will not produce a bunch of these warnings. I must say that I like this very much. This way we will be able to avoid Null Reference Exceptions in runtime.
Records
Ok, I am very excited about this for multiple reasons. For instance, I still can remember when I was just starting to code, and I was so confused with the way the operator ‘==’ works on primitives and the way it works on reference types. Take a look at this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int x = 1; | |
int y = 1; | |
retrun x == y; //retruns true | |
var x = new SomeType(); | |
var y = new SomeType(); | |
return x == y, //returns false |
So, this operator works in a way that is sort of expected for primitives, which is not the case for reference types. Of course, this is because C# compares reference types for referential equality, but we can all agree that this is really intuitive and it can be confusing. Enter the stage Record type, the idea that already exists in F#.
This type is basically just a collection of fields. All you will have to do is define it like so:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Student(string Name, decimal Gpa); |
The first benefit that we will have from this feature is that ‘==’ operator will now check the structural equality, and it will be more intuitive and natural, especially for newcomers to C#. The second (and huge) benefit is that this will save us from writing a bunch of boring, boilerplate code. The compiler will do all tedious work for us, and based on the upper definition of Record, it will generate something like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Student : IEquatable<Student> | |
{ | |
public string Name { get; } | |
public decimal Gpa { get; } | |
public Student(string Name, decimal Gpa) | |
{ | |
this.Name = Name; | |
this.Gpa = Gpa; | |
} | |
public bool Equals(Student other) // for IEquatable<Student> | |
{ | |
return other != null && Equals(Name, other.Name) && Equals(Gpa, other.Gpa); | |
} | |
public override bool Equals(object other) | |
{ | |
return this.Equals(other as Student); | |
} | |
public override int GetHashCode() | |
{ | |
return (Name?.GetHashCode()*17 + Gpa?.GetHashCode()).GetValueOrDefault(); | |
} | |
public Student With(string Name = this.Name, decimal Gpa = this.Gpa) => new Student(Name, Gpa); | |
public void Deconstruct(out string Name, out decimal Gpa) | |
{ | |
Name = self.Name; | |
Gpa = self.Gpa; | |
} | |
} |
Yes, that is a lot of code you don’t have to write anymore. This is not a ground-breaking alteration of the language, but it is still an awesome one. Check out the proposal for more information.
Async Streams and Async Dispose
As we can remember C# 5.0 was all about asynchronous programming. Nevertheless, a few C# features were left out from these innovations. One of those are asynchronous enumerations. By this, I mean that you cannot iterate through some collection in an asynchronous manner – all you can do is get all the elements this way. This leaves you with the fact that asynchronous use of LINQ is also impossible (or at least not done easily). The guys from C# team decided to change this. Basically, you should be able to do something that will look like this now:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
IAsyncEnumerable<Data> someData = | |
searchEngine.Get(query); | |
foreach await (var data in someData) { // … } |
As you can see, the idea is to have the IAsyncEnumerable which will return element by element asynchronously. Of course, this leaves a bunch of open questions as to how cancellation will be handled, and how this will affect code complexity. Apart from that, for this feature to be complete, full LINQ support will have to be done.
Another feature that was not enriched with asynchronous functionality is Dispose. We are still doing Dispose synchronously these days, except we don’t make a workaround that looks something like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
await Task.Run(() => disposableEntity.Dispose()); |
Naturally, this hack that we would place in our finally block is not something we want to do. So, idea is that something like this can be done:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using await (var disposableEntity = parent.Start()) | |
{ | |
// do important work | |
disposableEntity.SomeFunction(); | |
} |
In order to achieve this, C# will introduce a new interface IAsyncDisposable. To get more information on these features, check out the proposal here.
Default Interface Implementations
Did you just make your most skeptical face while reading this the paragraph title? I know that I did when I first read it. The question that popped instantly into my head was ‘Why would you put any concrete implementation in the interface when you have an abstract class for that?’. Still, allow me to explain what the idea behind this concept is.
Have you ever found yourself in a situation where you have to extend some interface with some functionality? I definitely have. And, the problem that occurred then is that all classes that were implementing that interface had to implement this new method. In that moment, I would ask myself ‘Do I follow Interface Segregation Principle?’. But, if you work on extensions for legacy systems, and you know you need backward compatibility, this feature will make your life much easier.
In a nutshell, you will be able to do this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface IPrintAddress | |
{ | |
void PrintAddress() { WriteLine("rubikscode.net"); } | |
} | |
class Blog : IPrintAddress { } // Doesn't cause error! | |
IPrintAddress i = new Blog(); | |
i.PrintAddress(); // prints "rubikscode.net" |
From what I understand, these implemented methods would become virtual methods of the interface, which implementation can override or not. This is one interesting feature, that will further reduce the difference between interfaces and abstract classes. To get more information on these features, check out the proposal here.
Extension Everything
This is the feature that I think is cool, but I am kind of afraid of its consequences. Nevertheless, it feels like a natural progression of the language itself. The idea is to apply the concept of extension methods from C# 3 to properties, fields, static fields and static methods. This way you will be able to add anything to a type.
Effectively, this means that you will be able to add a whole new functionality to a type, without touching the original code. In addition to that, the original code will not be able to interfere with this new functionality. That is great from the point of separation concerns. What I am having mixed feelings about is the way that this will affect the code itself. Even now, with just extension methods, the code can be somewhat complicated to understand. Still, perhaps I am mistaken and this new feature will actually clean that code up as it will contain the entire functionality.
The syntax will look like something like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extension ExtendedEntity extends Entity | |
{ | |
private string _additionalField = "AdditionalField"; | |
public string AdditionalField | |
{ | |
get | |
{ | |
return _additionalField; | |
} | |
set | |
{ | |
_additionalField = value; | |
} | |
} | |
public static void PrintSomething() => Console.Write("Someting"); | |
public void PrintAdditionalInfo() => Console.Wirte(_additionalInfo); | |
} |
Conclusion
Even though we will not see C# 8 anytime soon, I am super excited about some of the features that it could bring. Also, since these are just glimpses of features that could be introduced, I am curious about how these functionalities will be integrated under the hood. What do you think? Would these features help you in writing more elegant solutions?
Read more posts from the author at Rubik’s Code.
Just to let you know that the snippets of code don’t show up on mobiles.
Thank you, I just found out that Gists are not supported on some devices.
I will migrate this to some other provider, or find some other solution.
Sorry for your trouble, and thank you again for pointing it out.
Just tried it on iOS and Android devices, and it works fine.
I’ll investigate this fruther.
Thanks once again for pointing it out.
Cheers
They do appear when viewing the site directly, but when linking from Google, the mobile browser doesn’t come to the site directly, but to a Google proxy that hosts the site. In this case, the snippets don’t appear.
Hm, that is interesting, I will check out is there any support for this.
Thanks!
It feels more and more like MS is trying to make C# a dynamic language like JavaScript. This saddens me. I prefer C# because of its strictness. Previous changes to the language served as augmentations or readability improvements, but the recent changes only seem to reduce readability. Having many ways to write the same code can be confusing.
I use classes because I can make them null. I like this ability of reference types. And just like in C++, you have to use the feature with responsibility. I rarely get an NRE because (1) I’m careful, and (2) I use a static analysis tool like Resharper. What no one is mentioning is that there’s a difference between classes and structs beyond nullability: where they live in memory. Classes (reference types) live on the heap and are garbage collected, whereas structs live on the stack and cannot be collected. This should be the main argument for nullability reference types.
Also, interfaces and abstract classes should be different things. What is the reason for trying to merge the concepts?
In general, I like the concepts that are/will be borrowed from functional languages, but I also like some of the concepts that are borrowed from more loose languages, like TypeScript. In my opinion, C# is popular and simple enough, to incorporate both of those worlds, and keep the strictness you are mentioning. But time will tell…and I am feeling uneasy about some of these features.
The static analysis itself is a good indicator, but I saw a lot of code in which null is used for flow control. In my opinion, this is what is causing a lot of problems, and because of this, I like the strict definition for Nullable Reference Type.
Default Interface Implementations is the feature I like the least. It seems it will be misused, a lot. As I mentioned in the post, this way backward compatibility could be the main reason for this. For example, if you have an API that is used by old and new clients. If only new clients require some functionalities, this will be achieved rather easy, without complicating things for the old user. But then there is a question, should the old client have this new functionality exposed to her, or not. I still don’t get it, but once again, time will tell 🙂
Thanks for reading!
The other common case for default implementations are for things like .IsEmpty on IEnumerable. A default implementation could just call .Count and see if it’s 0 (or better yet, .Take(1).Count). But some implementations of IEnumerable could have a much more efficient way of discovering if they contain elements or not.
I appreciate IEnumerable is already done but there are many other interfaces where you have some methods that could be composed of others, but some implementations can be provided by specific classes because they can do it a better way.
This still sounds similar to abstract classes, but the key thing here is that you can only have one parent class even if you need to implemented 2-3 interfaces.
IRepository is another example (leaving aside whether IRepository is a good idea or not).
It can have a Get(ids[]) method and a Get(id) method.
Clearly the method taking an array of ids can have a default implementation which just loops over the ids and calls the singular Get(id) method. That may be very inefficient if you’re hitting a database but may well be fine if it’s all in memory.
Finally, if you’re a library author and need consumers to implement some interfaces, providing some default implementations on methods can be very friendly to those consumers. It also allows you to later optimise by adding an additional method which does something smart that some consumers may implement but many, including existing ones, will not. Think of a method that the library may call such as “preload”, which didn’t exist originally but could really speed things up. The default can do nothing, which breaks no one as that was the behaviour before anyway. This can be cleaner than making yet another interface.
It seems that Default Interface Implementation was inspired by Java, but I’d rather prefer Anonymous Interface Implementation in C#8 to avoid creating a class that implements a certain interface, for single use only.