C#7: Better Performance with Ref Locals, and Ref and Async Returns

Since the start of the year, we have been taking a look at the various new features coming to C# in C#7. This week, we will look at some of the changes to returning values from our functions that are there for those who need better performance. Before we begin, here is a summary of what we are covering in this series.

Generalized async return types

Up until now, an async method had to return Task, Task<T>, or void (though that last one is generally frowned upon1). However, returning Task or Task<T> can create performance bottlenecks as the reference type needs allocating. For C#7, we can now return other types from async methods, including the new ValueTask<T>, enabling us to have better control over these performance concerns. For more information, I recommend checking out the official documentation.

Ref Locals and Ref Returns

C#7 brings a variety of changes to how we get output from our methods; specifically, out variables, tuples, and ref locals and ref returns. I covered out variables in an earlier post and I will be covering tuples in the next one, so let's take a look at ref locals and ref returns. Like the changes to async return types, this feature is all about performance.

The addition of ref locals and ref returns enable algorithms that are more efficient by avoiding copying values, or performing dereferencing operations multiple times.2

Like many performance-related issues, it is difficult to come up with a simple real world example that is not entirely contrived. So, suspend your engineering minds for a moment and assume that this is a perfectly great solution for the problem at hand so that I can explain this feature to you. Imagine it is Halloween and we are counting how many pieces of candy we have collectively from all of our heaving bags of deliciousness3. We have several bags of candy with different candy types and we want to count them. So, for each bag, we group by candy type, then retrieve current count of each candy type, add the count of that type from the bag, and then store the new count.

This works, but it has overhead; we have to look up the candy count value in our dictionary multiple times when retrieving and setting the count. However, by using ref returns, we can create an alternative to our dictionary that minimises that overhead. In writing this example, I learned4 that since IDictionary does not do ref returns from its methods, we can't use it with ref locals directly. However, we also cannot use a local variable as we cannot return a reference to a value that does not live beyond the method call, so we must modify how we store our counts.

Now we are returning a reference to the actual stored value and changing it directly without repeated look-ups on our data type, making our algorithm perform better5. Be sure to check out the official documentation for alternative examples of usage.

Syntax Gotchas

Before we wrap this up, I want to take a moment to point out a few things about syntax. This feature uses the ref keyword a lot. You have to specify that the return type of a method is ref, that the return itself is a return ref, that the local variable storing the returned value is a ref, and that the method call is also ref. If you skip one of these uses of ref, the compiler will let you know, but as I discovered when writing the examples, the message is not particularly clear regarding how to fix it. Not only that, but you may get caught out when trying to consume by-reference returns as you can skip the two uses at the call-site (e.g. int count =_candyCounter.GetCount(candyName);); in such a case, the method call will be as if it were a regular, non-reference return; watch out.

In Conclusion

I doubt any of us will use these performance-related features much, if at all, and nor should we. In fact, I expect that their appearance will be a code smell in a majority of circumstances; a case of "ooo, shiny" usage6. I certainly think that the use of ref return with anything but value types will be highly unusual. That said, in those situations when every nanosecond of performance is required, these new C# additions will most definitely be invaluable.


  1. https://msdn.microsoft.com/en-us/magazine/jj991977.aspx 

  2. https://docs.microsoft.com/en-us/dotnet/articles/csharp/csharp-7#ref-locals-and-returns 

  3. Let's not focus on why we went trick or treating as adults and why anyone gave us candy in the first place 

  4. seems obvious now 

  5. In theory; after all, this is a convoluted example and I am sure there are better ways to improve performance than just using ref locals. Always measure your code to be sure you are making things better; don't guess 

  6. "Ooo, shiny" usage; when someone uses something just because it's new and they want to try it out 

C#7: Local Functions

We have been racing through the C#7 features in my latest series of posts; here is a list of what I have covered and what will be covered:

In today's post, we will look at local functions. Those who are familiar with JavaScript will be familiar with local functions; the ability to define a method inside of another method. We have had a similar ability in C# since anonymous methods were introduced albeit in a slightly less flexible form1. Up until C#7, methods defined within another method were assigned to variables and were limited in use and content. For example, one could not use yieldinside anonymous methods.

Local functions allow us to declare a method within the scope of another method; not as an assignment to a run-time variable as with anonymous methods and lambda expressions, but as a compile-time symbol to be referenced locally by its parent function. With lambda expressions, the compiler does some heavy lifting for us, creating an anonymous type to hold our method and its closures; also, to call them, a delegate must be instantiated and then invoked, which incurs additional memory overhead to standard method calls: none of this is necessary for local functions as they are regular methods. Not only that, but because these are regular methods, the full range of method syntax is available to us, including yield.

The official documentation provides a good overview of the differences between anonymous methods/lambda expressions and local functions, which ends with this paragraph:

While local functions may seem redundant to lambda expressions, they actually serve different purposes and have different uses. Local functions are more efficient for the case when you want to write a function that is called only from the context of another method.

The last sentence of that infers one of the most useful things about local methods; streaming enumerable sequences with fail early support. The yield syntax introduced in C#3 has been incredibly useful, simplifying the work necessary for defining an enumerator from writing an entire class to just writing a method. However, due to the way enumeration works, we often have to split our enumerator methods into two so that things like argument validation occur immediately, rather than when the first item in the sequence is requested, like this:

The NumbersImpl method is only ever used by the public-facing Numbers method, but we cannot make that any clearer. However, with C#7 and local functions, we can now embed that method declaration into the Numbers method and make our code explicit.

There are a couple of things to note here. First, we can declare the local function after it has been called; unlike anonymous methods and lambda expressions, local functions are just like any other method; they are part of the program declaration rather than its execution. Second, and somewhat surprisingly2, we can use closures.

Closures in Local Functions

With lambda expressions and anonymous methods, closures are hoisted into member variables of an anonymous type, but this is not how local functions work; local functions do not necessarily get their own anonymous type3. So how do closures work in local functions? Well, the compiler performs a little code-rewriting for us to effectively hoist the closures into method arguments so that we don't have to repeat ourselves.

In Conclusion

Local functions provide a valuable alternative to anonymous methods and lambda expressions, and one-time use member functions. Not only do they make a clear distinction between run-time and compile-time, making the intent clear, but also by co-locating a single-use method with the code that calls it, we can make our code more readable. Of course, as with many other features of high-level languages like C#, this could be abused and make code horribly unreadable, so keep each other honest and be sure to call out incorrect or dubious usage when you see it.

You can read more about local functions in the official documentation.

What do you think? Will you use this new feature of C#? Does it make the language better? Please leave your views in the comments. Next week, we'll take a look at some of the changes C#7 makes to returning values from our methods.


  1. Lambda expressions are a terser syntax for anonymous methods 

  2. at least to me 

  3. Local functions that implement enumerators do get an anonymous type, but that's a special case 

C#7: Pattern Matching

So far in this series on C#7, we have looked at some nice new things, including out variables, new expression-bodied members, throw expressions, and binary numeric literals. These are all great little additions, but this week, we get to a truly cool and long-awaited feature; pattern matching. But, before we get into that, here is the usual summary of what I am covering.

Pattern Matching

I will admit that I was a tad confused as to why this is called "pattern matching". I read the Wikipedia article1. I expect I would understand this more if I were a Computer Science major instead of Computer Systems Engineering2. According to Wikipedia:

In computer science, pattern matching is the act of checking a given sequence of tokens for the presence of the constituents of some pattern.

The What's New in C#7 documentation explains:

Pattern matching is a feature that allows you to implement method dispatch on properties other than the type of an object.

While I now understand the academic concept of pattern matching, I think we may regret using the term to specifically reference the features that are under its umbrella for C#7. I would have preferred it if these features had been introduced using already widely understood and consistent nomenclature. I think the official documentation agrees with me, since it almost immediately splits the feature into two pieces; is expressions and switch expressions. However, I am going to draw the line that divides the parts of pattern matching in a different place and call the two parts cast-conditional variables and case filters, because that fits better with my understanding of what they do.

Cast-conditional Variables

Many of us know the following code:

This is the efficient way of verifying a value is a given type and then consuming it as that type since we cast just once3. However, with the new cast-conditional feature, we can condense this down to:

The cast and the check of its success have been condensed into a single, easily understood statement.  We can use this cast-conditional variable syntax in any place where we might otherwise but a boolean expression:

This feels like a great improvement to me and fits really well with the similar out variable feature, however it is only a new way of writing something we could already do. When extended to the cases in switch statements (albeit with a slightly different syntax), this gives us a brand new ability; switching based on variable type:

Now you can iterate over that array of object values and have a nice, succinct way of processing the contents by type. Not only that, but with case filters, you can craft even finer conditions for your switches.

Case Filters

C#6 introduced the when keyword as a modifier to catch expressions so that we could finally utilize exception filters from C#. Now, the when keyword gets a similar job in switch statements as a modifier to case statements. Like in exception filters, the when expression is a condition that must be met for the case to be a match. For example, we could create an IsNumber method and use when to filter cases like Infinity and NaN:

Prior to C#7, this code would look something like this:

Not only was there more typing before C#7, but I think the code was more repetitive and harder to scan. This may be a convoluted example, but I hope it illustrates how valuable this new language syntax can be.

In Conclusion

Naming disagreements aside, the new pattern matching in C#7 is powerful. With that power comes responsibility; the responsibility to use it wisely and to call out others who do not, for there is surely great room for abuse with this feature. I envisage frequent and appropriate use of cast-conditional variables in if statements since the scenarios to which that caters are widespread. However, the filtering added to switch statements brings something entirely new and so, I do not see it being as widely adopted not as appropriately used; time will tell.

Overall, I love this addition to C#7 even though I do not like the name. What do you think? Does "pattern matching" make sense or should it be something like "cast-conditional variables" and "case filters" instead? Will you use this feature a lot? When might you find pattern matching useful? Sound off in the comments and discuss.

 


  1. that's a lie; I read parts of it until I came to the conclusion that it was not helping 

  2. Is this a theory versus practice issue again? I face those often in this field 

  3. Using the is condition and then casting inside the if statement would cause two casts; one for the is and another for the cast 

C#7: Throw Expressions and More Expression-bodied Members

In this installment of my look at C#7, we will take a look at some nice syntactical enhancements, including the first ever community contribution to the C# language implementation. Before we get started, here is a summary of what I am covering in this series on C#7.

Throw Expressions

We have all written code like this1:

I have omitted the exception arguments for brevity, but you should hopefully recognise the sort of sanity checking to which I am referring within the highlighted lines.

With throw expressions, we can now combine assignment, the null-coalescing operator2, and throw to create succinct validation code. This means that the example above can be simplified to not even need the constructor.

The highlighted lines are equivalent to the code we had earlier, but now we are able to use throw as part of the expression. The introduction of throw expressions means that we can now throw exceptions in conditional and null-coalescing expressions, as well as some lambda methods where it was previously not possible to do so. Not only that, but when combined with expression-bodied members, we can write some very expressive yet terse code.

Expression-bodied Members

With C#6 we got expression-bodied members, which allowed us to express simple methods using lambda-like syntax. However, this new syntax was limited to methods and read-only properties. Via the first ever community contribution to C#3, C#7 expands this syntax to cover constructors, finalizers, and property accessors.

If we take the property example we had before, containing our throw expression as part of  property set accessor, we can now write it as:

I won't bother with examples for constructors or finalizers; the main documentation is pretty clear on those and I am not convinced the syntax will be used very often in those cases. Constructors are rarely so simple that the expression-bodied syntax makes sense, and finalizers are so rarely needed4 that most of us will not get an opportunity to write one at all, expression-bodied or otherwise.

In Conclusion

These simple additions to the C# syntax enable us to write terse code without losing clarity, which is always a good thing. Not only that, but we have reached a landmark event; community contributions to C#. This contribution may be a little tame when compared with some of the other features coming in C#7, but it bodes well for the future of the language in its new, open source home.

Next time, we will take a look at the highly anticipated pattern matching. Until then, feel free to leave a comment, or read more about C#7 on my blog and on the official documentation.


  1. Let's ignore the nastiness of throwing exceptions during construction 

  2. You remember Elvis, right?? 

  3. Source: https://docs.microsoft.com/en-us/dotnet/articles/csharp/csharp-7#more-expression-bodied-members 

  4. If you find yourself writing a finalizer, I recommend you make sure you really need it; there is probably a better way 

C#7: Out Variables

Last time, we started to look at the new features introduced in C#7. Here is a quick refresher of just what those features are:

In this post, we will look at one of the simplest additions to the C# language; out variables.

int dummy

How often have you written code like this?

Or this?

Sometimes you use the out value retrieved, sometimes you do not, often you only use it within the scope of the condition. In any case, there is always the variable definition awkwardly hanging out on its own line, looking more important than it really is and leaving space for it to accidentally get used before it has been initialized. Thankfully, C#7 helps us tidy things up by allowing us to combine the variable definition with the argument.

Using the out variable syntax, we can write this:

In fact, we do not even need to declare the type of the variable explicitly. While often we want to be explicit to make it clear that it matters (and to ensure we get some compile time checking of our assumptions), we can use an implicitly typed variable like this:

In Conclusion

out variables are part of a wider set of features for reducing repetition (in written code and in run-time execution), and saying more with less (i.e. making it easier for us to infer intent from the code without additional commentary). This is a very simply addition to C# syntax, yet useful. Not only does it reduce what we need to type, it also improves code clarity (in my opinion), and reduces the possibility of silly errors like using a variable before it has been initialized, or worse, thinking that it being uninitialized was a mistake and hiding a bug by initializing it.

Until next time, if you would like to tinker with any of the C#7 features I have been covering, I recommend getting the latest LINQPad beta or Visual Studio 2017 RC.