As part of the final entry in the C# Advent series of 2019, Calvin Allen touched on some proposals in the C# 9 language that he was most excited about. It’s a quick, well-written, and exciting article you should check out and one I’ll expand on here.
Go ahead. I’ll wait.
Great! Now that you’re back, lets talk about the aspects of C# 9 that I’m really excited about as it supports more functional programming techniques.
So, with this preamble out of the way, what is it about C# 9 that gets me really excited?
Note: All items here are proposals and not final in syntax or in their inclusion in the next version of C#. Still, it’s good to look ahead at what may be coming. For full proposal details, see the C# 9 Milestone on GitHub.
Simplified Null Validation
Let’s start off with something simple.
C# 9’s proposal allows for the following syntax:
Note the exclamation mark next to brain
.
This is the equivalent of the following code:
As you can see, this feature would simplify argument validation and potentially make the argument validation visible to upstream callers via IntelliSense.
My initial thoughts on this feature are that I like it and likely will use it, but prefer C# 8’s existing null validation to this. Combining the two would be fine, but more for readability and documentation.
Still, this is a feature that would help instrument legacy C# codebases.
Primary Constructors
C# 9 has proposals that would allow you to simplify class constructors in the same way that you can in TypeScript.
Instead of writing the following code:
You can instead use this code:
As you can see, this is a significantly smaller amount of code. I frequently say that code you don’t have to write won’t break and this is one of those cases.
By keeping your constructor logic minimal, you eliminate redundant boiler plate code that encourages skimming code files instead of doing a real code review. By having less code, we make it harder for bugs to hide by making our code more meaningful.
As an aside, this is one of the things I love about F#, so I am happy to see anything that helps C# have similar levels of conciseness.
Record Classes
Records are so similar to primary constructors that I’d almost say they’re a minor syntax tweak variant of primary constructors.
Let’s say you need an object that holds a certain amount of information, yet has no need for methods. This is essentially a record or a piece of data.
You can use primary constructors to declare the fields of the object, then end the class definition with a semicolon instead of declaring an empty body:
In general I’m not in favor of record classes in object oriented programming, except as they apply to minimal functional programming languages like F#.
As we’ve seen in recent releases of C#, the language is supporting more and more aspects of functional programming and I view this feature as a stepping stone to enable and expand more advanced features like discriminated unions.
Discriminated Unions via Enum Classes
My number one wish for the C# language is support for Discriminated Unions and matching on various types. Incidentally, this is my number one favorite feature in F# as I’ve written previously.
If you’re not familiar with Discriminated Unions, they say that an object can be one of X different possibilities and your code can match off of these possibilities and take appropriate action based on which type it is.
C# currently has some support for this type of behavior via inheritance and overloading to some extent, but proper discriminated unions are concise and do not require object oriented features in order to work.
C# 9 has a feature proposal to support Discriminated Unions in the language.
Take a look at the following class definition, noting the use of enum class
syntax and the use of Records and primary constructors:
You could then potentially match on a game card in code via a switch expression like the following:
I should note that of the features I’ve discussed, this is likely the most volatile at the moment. There are a lot of different ideas being thrown around on how this should work and if it should even exist in the language.
My personal opinion is that it should exist. I’ve previously turned to libraries like OneOf to experiment with Discriminated Unions in C#, but was disappointed by some aspects of that library as I discussed in a prior article.
Give us support for Discriminated Unions in C# and you’ll begin to see more possibilities emerging that offer a hybrid between functional programming and object oriented programming, as well as improved integration between F# and C#.
Closing Thoughts
As I mentioned earlier, C# is clearly trending towards supporting more functional programming techniques – for those who want to use them.
This trend something that may irritate some, but the ability of .NET and the C# language to adapt over the decades is one of the key reasons I love the language and framework, as I wrote earlier this year.
Again, these features are not guaranteed for C# 9 and are not necessarily in their final form. Stay tuned for more news on their development as we get closer to C# 9’s release.
And, once again, thanks to my friend Calvin Allen for highlighting these technologies in his blog post in the collaborative C# Advent series.
I look forward to seeing how these features change over time and what C# 9 will fully bring to the table.
The post The Dream of C# 9.0 appeared first on Kill All Defects.
Top comments (23)
I really wish they would bring in discriminated unions to C#. Ever since I started using them in F# I've missed them in every other language I've used.
Same here. Typescript comes close though.
Typescript doesn't come close. It goes way above and beyon with it's intersection, union, mapped and conditional types. I worked on a project where I was in charge of frontend (ts) and my coworker was doing backend (.net) and we wanted to move some logic from client to server. And it just wasn't possible to write without using
dynamic
which throws all compile time checks out of the window.While I agree that the TS type system is awesome, discriminated unions in TS are a bit clunky, compared to Haskell/F#. Would be good to see them become a first class concept in TS, and not a side-effect of the super flow analysis.
When you think the language is done, the guys from the C# team keep adding things. It never ceases to amaze me how they come up with new ideas and implementations. I love it!
The C# team is quite amazing. They keep introducing features to make the language better; the amazing aspect of it is that they always design new features to be idiomatic and feel "C#" in nature. What an elegant and multipurpose language C# is.
Can the declarations inside those discriminated unions theoretically be inline functions? I know in your example you're providing the arguments and doing a little logic in the switch, i'm wondering if you could also do that kind of thing in the constructor. Maybe it wouldn't be helpful though. Cool article!
Possibly. I couldn't find as many examples of working with Discriminated Unions in the feature proposal thread. I went with the switch expressions to try to get the syntax looking as close as F#'s Match expressions as possible while still working with existing C# syntax.
Some of the features I'd like to see in C# are borrowed from Midori's programming language (which evolved from Sing#, which evolved from Spec#), F# functional programming language, and D programming language.
C# Code Contracts that were backported from Spec# are broken. Besides being dog slow, they don't compose polymorphically. That kind of facility needs to be in the core language, not a bolt-on terribly slow afterthought. Here C# could take a page out of D's playbook
Unit testing should be part of the core language. I've used NUnit, and I've used xUnit.net, and there are others. The problem with them is that they all solve that problem space their own way, so there's lock-in for something that ought to be a core language construct. (As long as I have the magic of NCrunch, I'm only complaining about the lock-in. The test runners can do their own thing their own way with their own reporting models.) Another page out of D's playbook.
The key concept I've picked up on from Midori is bugs are not recoverable errors. That notion is not something that C# has learned.
The other neat thing in Midori is that calling a method that could throw an exception requires notation at the callsite:
var y = try blah();
The required try there makes the "invisible goto" no longer invisible.F# has too many awesome things to list. I wouldn't mind seeing more F#-isms in C#, with due consideration. But C# will never be F#. They serve different programming purposes, and are suitable programming language tools for different domains. And that's a good thing.
C# not having non-nullable references from the get-go was a mistake, and I'm happy to see that this trillion dollar mistake is being addressed. (Sir Tony Hoare's mistake in ALGOL W was merely a billion dollar mistake. C# is much more widespread.)
Hey! What color scheme is that?
For some of my smaller examples - especially those featuring future language features, I use Carbon to create code example visuals.
This is the
A11y Dark
scheme. You can find out more about Carbon at carbon.now.sh/I believe most of their color schemes are based on IDE configs, so you might be able to find it for your editor of choice by searching for "A11y Dark"
Okay! Thanks!
I love C#. It is improving and getting better every release. C# is a true multipurpose programming language. You can use it to develop the web, IoT, desktop solutions, server application, machine learning and big data manipulation, games as well as mobile app.
Thank you for your writeup- I really enjoyed reading it.
Some of these features have been promised since C#6.
While I appreciate the F# love if you want the features why not just use F#.
If you follow me, you'll see that I do.
Awesome! Why the Egyptian brackets, though?
Good catch. I do TypeScript and C# examples frequently and use different bracket styles for each. Here I used my TypeScript brackets on accident.
As pretty as the discriminated unions are, I was taught that if I am switching based on an object type, it is a code smell that I probably should be using polymorphism and the strategy pattern.
And that largely holds true for object-oriented programming. DUs are more for supporting the functional flows of application logic.
Are
enum class
declarations automaticallysealed
?