C# 7, “out var” and changing variable scope

C# 7 is due to be released along with Visual Studio 2017, which is currently available as an “RC” release. I had previously regarded it as a thoroughly unexciting “meh” release, for – beyond new syntactic tuple features – the changes were minor and not really worth getting excited (or even angry, depressed etc) about. Then just before that RC release, the language team made a change to the way the out var feature works. And suddenly that all changed. This minor feature has become a significant change to the language. And many people aren’t at all happy about it.

Update 2: since writing this, the rules around variable scope leakage have changed. This article is no longer an accurate description of those rules. Please see C# 7, “out var” and changing variable scope, revisited for details.

Update: due to a lot of feedback that the “sensationalist” tone here was distracting people from the content, I have re-posted this in this new, much more toned-down, form.

If you aren’t aware of what out var is, it started out as a simple syntactic sugar feature for allowing the variable associated with an out parameter to be declared as part of the method call, rather than needing to be declared in a prior statement. For an example of its use, consider:

Now to my mind, out parameters are an anti-pattern as they allow values to leak out of a method via the back door, rather than being part of the return value. With C# 7 introducing syntactic tuples, even those that haven’t caught the functional “maybe/option” bug really have no excuse to use out parameters other than with legacy APIs. But some folk really like them and use them in their own methods. out var appeared to be a nice little addition for these people. So what’s all the fuss about, surely it’s a harmless little feature that can be ignored by those who don’t want to use it?

It’s not quite as simple as that. To explain why, consider the following two use-cases for out var:

These are common ways that people will want to use out var. Further, the language design team like writing code like this. So the decision was made to change the language so that these use-cases would work. In other words, the following statements are now semantically identical:

To achieve this, the use of out var had to result in the scope of the variable leaking out into the enclosing block. This has set alarm bells ringing for many as this is how JavaScript works, and it’s wildly regarded as one of the worst design decisions of that language. The C# language team appear to have decided that C# should copy one of the worst features of one of the most badly designed languages.

So as of C# 7, the following code snippets all compile and work, thanks to variable scope leakage:

If that were the extent of it, it might still not be worth getting too exciting about. Unfortunately though, these leakage rules vary depending on the language construct used.

The first variation is with for and foreach loops, and using blocks. They already support the concept of declaring variables as part of the expression and the scope of those variables do not leak out into the surrounding scope. So the decision was made that out var‘s declared in the expression of a for or foreach loop or using statement will not leak into the surrounding scope:

Next, switch statements introduce a third different behaviour. Taken by themselves, the rules around out var scope in switches are very sensible and useful, but they are at odds with all the previous rules, which is likely to cause confusion. They can be summed up with the following piece of code:

As you can hopefully see, with switch statements, the scope is restricted even further than with for, foreach and using, in that the scope is restricted to each case.

There is one last “gotcha” to be aware of: the is var construct. This is a nice addition to the language and is at the vanguard of proper pattern matching being added to C#. To clarify, whilst is var is genuine syntax, is will likely mainly be used with specified types to avoid the old is/as syntax:

but is var seems a neat way of referring to this syntax.

Consider the following code:

The answer is, you get a compiler error: “Use of assigned variable ‘i'”. So is var‘s follow the same rules as out var‘s, but there’s a gotcha that most of the time, you can’t use that leaked variable as it can’t be guaranteed to have a value.

So let’s recap on these scope changes:

  1. C# 7 will introduce a new feature of out var that simplifies the use of out parameters,
  2. To be genuinely useful to those that like to use out var‘s, variables declared via out var need to leak out into the surrounding scope,
  3. But they only really need to leak with if statements, so an out var variable declaration in an if is semantically equivalent to declaring the variable before the if,
  4. It doesn’t make sense for them to leak out of for foreach and using and, if they did leak, that would be counter to the way other variables declared in such constructs behave. So they don’t leak in these cases.
  5. For “type switching” to work, out vars in switch statements are confined to the case they are declared in. This is consistent with, but slightly different to, for, foreach and using, but runs counter to if. if and switch are no longer interchangeable constructs as their variable scope leakage rules are utterly different.
  6. out var‘s in while loops leak in the same way as if, not as for and foreach. It’s unclear why this decision was made though.
  7. C# 7 also introduces a nice new x is T y (or is var) feature that saves having to write x is T ... var y = (T)x style code. In order to keep things consistent with out var, the scoping rules are the same, except that the resultant variable cannot be read in most cases in that outer scope.

If you have the stamina (and be warned, these threads are seriously long), you can read the gory details of how the team announced this, and how the community reacted to it on Github: C# Design Notes for Jul 15, 2016 and even more so on this issue, which drove the issue originator to remove themselves from Github completely!.

2 thoughts on “C# 7, “out var” and changing variable scope

  1. As soon as I saw the spec I tweeted that ‘out var’ will proliferate out variables through code, something I don’t feel is a positive effect.

    We’re doomed.

  2. Typo: “Use of assigned variable ‘i’” should be “Use of unassigned variable ‘i’”

    Nicely summarised.

    In “normal” code I’ve found out vars and is T vars to be rather natural.

    The biggest issue I’ve had, after getting my head around the unassigned issue, is where I’d like the value of an is T var to be returned as the value of an out parameter. You have to create a new variable only to assign it to the out parameter, in an if then clause, setting the out parameter to null in the else clause.

    Or leave the code as a couple of lines using as and a null check.

Leave a Reply