In Part 1 and Part 2 we saw how C# formed and evolved along the years, from its inception in 2000 up to C# 6.0 release in 2015. Initially, C# was born as a strictly typed object-oriented language. It was influenced somewhat by Java and Delphi and was even called a Java imitation by James Gosling , the creator of the Java.
In later versions, C# evolved and adopted some functional programming attributes with Lambda Expressions, LINQ and Extension Methods. C# gained incredible traction and popularity with those features. After C# 3.0 in 2008, it became the 7th most popular language according to the TIOBE index .
Going still further in the time, C# imitated F# asynchronous workflows and created the async/await feature. C# also improved COM interoperability catching up to Visual Basic .NET, which was the COM reigning king up to that time. After C# 4.0 in 2010, its popularity rises and it becomes the 4th most popular language in the world according to the TIOBE index.
We saw that while C# imitated most of its features from existing languages (as would be expected from a programming language), it does so very well, often better than the original innovator. C# had some incredible innovations as well like LINQ.
In this article, we will see C# evolving towards a completely different area than the previous versions, and trying to become the one language that ruled them all.
C# 7.0
C# 7.0 is released in March 2017. By now, the new Roslyn compiler is alive and kicking, which allows the C# team to release many minor features quickly.
- Tuples
– Tuples were available before C# 7, but they had no language support. Each item was referenced as Item1, Item2, etc. C# 7.0 adds a very convenient syntax and language support to Tuples: ```
(string Alpha, string Beta) namedLetters = ("a", "b"); ``` ```
private static (int celsius, int fahrenheit) GetTemperature() { ... return (c, f); } ``` Tuples [already existed in Python](https://docs.python.org/2/tutorial/datastructures.html#tuples-and-sequences) and [in Scala](https://en.wikibooks.org/wiki/Scala/Tuples). **Imitation**
NOTE: When I call something ‘Imitation’, I will show at least one example of a programming language with the same feature existing before C#. But I don’t mean to claim that language is the original source of the feature.
- out variables
– We can now declare the out variable inline in the method. ```
// before int number1; int.TryParse(input, out number1)) // now int.TryParse(input, out int number2)) ``` A most welcome addition if you ask me. The out parameter is by itself unique to C#, so there’s no verdict on this one.
- Discards
– You can use the special underscore _ character for variables that you won’t need later. Useful when deconstructing tuples and when using out parameters.
```//returns name, license info, etc. but we care just about bithday and address var (_, _, birthday, _, address) = GetCurrentUserDetails(); ``` Already [used in Python](https://stackoverflow.com/questions/5893163/what-is-the-purpose-of-the-single-underscore-variable-in-python/5893946#5893946), in [Scala](https://stackoverflow.com/a/8001065/1229063), and there’s a [similar functionality](https://stackoverflow.com/a/23924610/1229063) in **Perl**. **Imitation**
- Pattern Matching
– The code speaks for itself: ```
// 'is' type pattern if (shape is Square square) return square.Side * square.Side; // in 'switch' statements switch (shape) { case Square square: return square.Side * square.Side; // 'when' clauses in 'case' expressions switch (shape) { case Square sqr when sqr.Side == 0: ``` I was very pleased when these got out. As far as innovation, [Scala](https://kerflyn.wordpress.com/2011/02/14/playing-with-scalas-pattern-matching/) and [Kotlin](https://programmingideaswithjake.wordpress.com/2016/08/27/improved-pattern-matching-in-kotlin/) already have similar pattern matching and C# is playing catchup here. **Imitation**
NOTE: This article is not meant to be judgmental. I do not mean to say that imitation is a bad thing. Both imitations and innovations are necessary to create a great language.
- ref locals and returns
– Allows references to variables, much like pointers in C. ```
int[,] matrix = ... ... ref var item = ref MatrixSearch.Find(matrix, (val) => val == 42); //assuming the cell found is (4,2) item = 123; Console.WriteLine(matrix[4, 2]); //prints '123' ``` As mentioned this is really a lot like C pointers. The innovation is that C# is in a garbage-collected runtime where memory buffers can move around (that’s why there are scope limitations and it’s just for *locals*). **Innovation**
- Local Functions
– Nesting functions inside other functions to limit their scope and visibility. ```
public static void ShowXTimes (string str, int x) { for (int i = 0; i < x; i++) { Show(x) } void Show() { Console.WriteLine(str); } } ``` Already existed in [Python](https://realpython.com/inner-functions-what-are-they-good-for/) and [JavaScript](https://www.tutorialspoint.com/javascript/javascript_nested_functions.htm). **Imitation**
- More expression-bodied members
– A new syntax for methods and properties: ```
// Expression-bodied constructor public ExpressionMembersExample(string label) => this.Label = label; private string label; // Expression-bodied get / set accessors. public string Label { get => label; set => this.label = value ?? "Default label"; } ``` I wouldn’t call it a new language feature, just a new syntax for an existing feature.
- throw Expressions
– You can throw exceptions in conditional expressions. ```
private ConfigResource loadedConfig = LoadConfigResourceOrDefault() ?? throw new InvalidOperationException("Could not load config"); ``` F# has if-then-else which[ acts as an expression](https://fsharpforfunandprofit.com/posts/control-flow-expressions/). So you can write in a similar fashion: ```
F#: let res = if (y = 0) then failwith "Divisor cannot be zero." else x / y ``` **Imitation** Thanks to Reddit user AngularBeginner for the correction
- Generalized async return types – Methods declared with the async modifier can return other types in addition to Task and Task<T> like ValueTask<T>. Another improvement to an existing C# feature implementation.
- Numeric literal syntax improvements
– Binary number 0b prefix, and _ digit separator for long numbers. ```
public const int Sixteen = 0b0001_0000; ``` Both features already existed in **Python**: [0b prefix](https://docs.python.org/dev/whatsnew/2.6.html#pep-3127-integer-literal-support-and-syntax), [digit separator](https://stackoverflow.com/a/38155210/1229063). **Imitation**
C# 7 is playing some catchup here with Tuples and Pattern Matching. These create extremely nice syntax and its part of the reason other languages like Python and Kotlin keep getting popular. Better late than never I say.
The ref locals feature is the beginning of a new strategy for C#, which will see more of later on. It allows more low-level control with the language, which in turn allows improving performance in algorithms and bottleneck pieces of code.
C# 7.1
In August 2017 C# 7.1 is released. It’s the first version which is not a round number. The language team seems to have decided to release smaller versions, but faster.
With 7.1 you can now configure the compiler to match a specific version.
async
Main
method – The entry point for an application can have the async modifier.
This is an Innovation and was later imitated by Python with async def main() and Kotlin with fun main() = runBlocking<Unit> {
NOTE: The research in this article, though thorough and long on my part, is not academic. I can make mistakes, so please comment or email me if a mistake is found and I’ll correct it.
- default literal expressions
– You can use default literal expressions with the default keyword when the target type can be inferred. ```
//before C# 7.1 int x = default(int); //with c# 7.1 int x = default; ``` More of a syntax sugar than a feature, so no verdict on this one.
- Inferred tuple element names
– The names of tuple elements can be inferred from tuple initialization. ```
int count = 5; string label = "Colors used in the map"; // before c# 7.1 var pair = (count: count, label: label); // with c# 7.1 var pair = (count, label); ``` This is another bit of syntax sugar, so no verdict here either. On a side note, a similar syntax is used in JavaScript [as of ES2015](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_2015).
Not much to say about this version. Nothing revolutionary, mostly some sugar syntax features. It’s nice to see versions being released so quickly.
C# 7.2
Version 7.2 is released in November 2017, after only 3 months after the last release.
- Span<T> and Memory<T>
– Holds a pointer to a range of an array (part of it or all of it). So if you have a byte array of 1..50, then you can have a Span<byte> pointing to range 10..20.
Python’s slicing notation is very similar to this feature and in fact, more powerful. Imitation
Looking at Python’s capabilities comes with a nice promise of what Span<T> can become in future versions.
Even though it’s an imitation, it’s impressing that the C# team was able to achieve this with all the existing language use cases and limitations. - Techniques for writing safe efficient code
– A combination of syntax improvements that enable working with value types using reference semantics. This includes:
- The in modifier on parameters, to specify that an argument is passed by reference but not modified by the called method.
- The ref readonly readonly modifier on method returns, to indicate that a method returns its value by reference but doesn’t allow writes to that object.
- The readonly struct declaration, to indicate that a struct is immutable and should be passed as an in parameter to its member methods.
- The ref struct declaration, to indicate that a struct type accesses managed memory directly and must always be stack allocated.The first 3 features seem to be inspired by the various const modifiers in C++
. Imitation
However, the last item ref struct is an Innovation.
- Non-trailing named arguments
– Named arguments can be followed by positional arguments. ```
PrintOrderDetails(productName: "Red Mug", 31, "Gift Shop"); // Note that 31 is used without specifying name ``` I might be missing something but it seems C# is the only language to implement this. **Innovation**
- Leading underscores in numeric literals – Numeric literals can now have leading underscores before any printed digits int binaryValue = 0b_0101_0101;. A small nice-to-have syntax improvement.
private protected
access modifier – Theprivate protected
access modifier enables access for derived classes in the same assembly. Java did have a private protected modifier (now obsolete) in Java 1.0, which was removed as of JDK 1.0.2 (the first stable version). The obsolete modifier was defined as follows:I read it 10 times and still can’t understand if it’s the same thing… Since it was never released in Java and due to the benefit of the doubt, I’ll tag it as an InnovationThe meaning of private protected was to limit visibility strictly to subclasses (and remove package access).
C# continues its strategy to allow better performance by letting the programmer low-level control. This strategy is already paying off. Span<T> and Memory<T> are used in .NET Core internal libraries to significantly increase performance.
C# 7.3
This version really focuses on improving safe code performance. The entire concept of unsafe code in a garbage collected environment is a C# Innovation, and doesn’t exist in any other garbage-collected environment (see fixed statement ). So there’s no reason to determine if the following is an innovation or imitation since it’s all unique to C# anyway.
- Access fixed fields without pinning – Allowing accessing fixed fields` indexer without additional pointer
- You can reassign ref local variables – Solving an existing feature’s limitation
- You can use initializers on stackalloc arrays – A nice syntax improvement to the existing stackalloc feature
- You can use fixed statements with any type that supports a pattern
- You can use additional generic constraints
The following enhancements were made to existing features:
- You can test
==
and!=
with tuple types – Already existed in Python Imitation - You can use expression variables in more locations – Relevant to out arguments, which are unique to C#.
- You may attach attributes to the backing field of auto-implemented properties – Here is an example: ```
[field: SomeThingAboutFieldAttribute] public int SomeProperty { get; set; } ``` I wouldn’t call it an innovation exactly since no other language has both Attributes and Properties. Java already [supports](https://en.wikipedia.org/wiki/Java_annotation) annotations for Methods and Variables.
- Method resolution when arguments differ by in has been improved
- Overload resolution now has fewer ambiguous cases.
It seems the entire 7.x C# versions are related to improving unsafe code, pointers, and low-level memory management. In other words, C# aims to become as efficient for algorithms as C and C++.
That’s a pretty bold goal, but theoretically, this can be achieved in specific bottleneck algorithmic blocks of code. C# can effectively disable the garbage collection by pinning variables, and use the new ref and stackalloc capabilities to work on the stack with pointers, just like native C++ code. Whether algorithms will start getting written in C# remains to be seen.
With version 7.3 we effectively covered all C# versions until today. Now, it’s time to see what will happen in the future. But first, let’s see how C# is doing in terms of popularity in 2018.
C# Popularity
In recent years, C# notably isn’t used much in startups . That role is mostly filled by Java, JavaScript, Ruby, and Python. Nevertheless, C# remains to be extremely popular in the industry. StackOverflow’s survey of 2018 places C# as the 4th most popular programming language (3rd if discarding SQL). .NET Core is the 3rd most popular framework after Node.js and AngularJS.
For the fifth year in a row, JavaScript was the most commonly used programming language, according to Stack Overflow survey pic.twitter.com/owjCst7MMP
— Rafael Kapela (@kapela) 28 November 2018
The TIOBE index places C# in 6th place, right after Visual Basic .NET (yes, really). The PYPL index places C# in 4th place after Python, Java, and JavaScript.
C# 8.0
We are getting very close to C# 8.0 release, which is said to come out with the Visual Studio 2019 preview by year’s end .
Mads Torgersen, the Program Manager of C#, recently wrote about all the new features in C# 8. Let’s go over them and see which are innovations and which are imitations:
- Nullable reference types – All our reference types, nullable by default will now show a compiler Warning when assigned null: ```
string s = null; // Warning: Assignment of null to non-nullable reference type string? s = null; // Ok ``` With this, Microsoft is finally dealing with the [Billion Dollar Mistake](http://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions). So as not to hurt existing code, this setting is configurable. Typescript implemented a similar feature with [strict nullable types](https://github.com/Microsoft/TypeScript/pull/7140). **Imitation**
- Async Streams – Allows to await foreach on asynchronous methods and yield return results: ```
async IAsyncEnumerable
GetBigResultsAsync() { await foreach (var result in GetResultsAsync()) { if (result > 20) yield return result; } } ``` I figure it’s like [BlockingCollection’s GetConsumingEnumerable](https://docs.microsoft.com/en-us/dotnet/api/system.collections.concurrent.blockingcollection-1?view=netframework-4.7.2) for async methods? I’ll have to ask Mads myself… But if I figured right it’s an **Innovation** - Ranges and Indices – Adds the Index type which can act as an index in arrays: ```
Index i1 = 3; // number 3 from beginning Index i2 = ^4; // number 4 from end int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; Console.WriteLine($"{a[i1]}, {a[i2]}"); // "3, 6" ``` and a new Range syntax, whose type is undecided but will probably be Span<T> ```
var slice = a[i1..i2]; // { 3, 4, 5 } ``` Both of those features exist in a similar fashion in Python with [negative indexes](https://www.quora.com/What-is-negative-index-in-Python) and [slice notation](https://stackoverflow.com/questions/509211/understanding-pythons-slice-notation/4729334#4729334).
- Default implementations of interface members – Kind of like in abstract classes, an interface can provide a default implementation which the implementing class can choose to override or not. After a very long while, C# imitates a feature that first appeared in Java
. Imitation
This raises questions about the difference between abstract classes and interfaces and also about problems with multiple-inheritance. This Java article refers to some of those questions and it’s also relevant to C#. - Recursive patterns – This is a really interesting progress in pattern matching: ```
IEnumerable
GetEnrollees() { foreach (var p in People) { if (p is Student { Graduated: false, Name: string name }) yield return name; } } ``` In this example, if p is Student **and** p.Graduated is false **and** Name is not null, then Name is returned. If you’re like me you probably had a hard time to wrap your head around this syntax at first. In my opinion, it’s a bit more intuitive to write if (p is Student st && !st.Graduated && st.Name!= null) yield return name; This recursive patterns already existed [in Rust](https://doc.rust-lang.org/book/2018-edition/ch18-00-patterns.html) and in [Erlang](http://erlangbyexample.org/pattern-matching). **Imitation** Thanks to Reddit user MEaster and to Daniel WM for the correction - Switch expressions – A new syntax for switch pattern matching: ```
var area = figure switch { Line _ => 0, Rectangle r => r.Width * r.Height, Circle c => Math.PI * c.Radius * c.Radius, _ => throw new UnknownFigureException(figure) }; ``` It’s very similar to [Kotlin pattern matching syntax](https://programmingideaswithjake.wordpress.com/2016/08/27/improved-pattern-matching-in-kotlin/).
- Target-typed new-expressions – When an object type can be derived from the expression, it’s allowed to be omitted: ```
Point[] ps = { new (1, 4), new (3,-2), new (9, 5) }; // all Points ``` An **Innovation** (for a statically typed language at least)
The big feature in C# 8 is the Nullable reference types. Hopefully, it will allow for safer code and much fewer Null-Reference-Exceptions.
The other features are mostly nice-to-have additions, and the Recursive patterns will probably take some getting used to…
Summary
This last article sums up all C# features from the first version release in 2002 up to C# 8 due to be released at the end of 2018. We also saw how C# gained traction along the way, remaining consistently one of the most popular languages in the world.
It’s quite incredible all the turns and changes C# took during all those years. I think it became one of the only truly multi-purpose languages in existence. Consider the following paradigms that exist in parallel in the C# language:
- It’s object-oriented
- It’s functional (LINQ, extension methods)
- It’s managed (garbage collected)
- It utilizes pointers and unsafe code like an unmanaged language
- It’s statically typed
- It can be dynamic (with the dynamic keyword)
From the comments I received, these articles were somewhat controversial. Some people thought I was trying to be judgemental, and there was no point in it. My point wasn’t to judge though. Rather I wanted to explore the history of the C# language and how it fared and evolved along the years in the context of other languages.
Anyway, I hope you got some benefit from the series, perhaps discovering a few C# features you didn’t know about (I sure did). I’d love to hear your feedback in the comments below and subscribe to the blog to get notified on new articles.