C# 7 Series, Part 4: Discards

Sometimes we want to ignore values returned from a method, especially those out arguments, a typical example is to check whether a string can be parsed to another type:

 bool parsedValue;
if (bool.TryParse("TRUE", out parsedValue)) { /* Do your stuff */ }

Here we want to ignore parsedValue. We also want to make this variable inaccessible so developers cannot reference it.

The C# 7.0 has a new feature called discards, which can be used to achieve our goal for this scenario.

Discards

Discards are local variables which you can assign but cannot read from. i.e. they are “write-only” local variables. They don’t have names, instead, they are represented as a _ (underscore.) _ is a contextual keyword, it is very similar to var, and _ cannot be read (i.e. cannot appear on the right side of an assignment.)

If we apply the discard to above code, it will look like this:

 if (bool.TryParse("TRUE", out bool _)) { /* Do your stuff */ }

Because _ is unreadable, it will not appear in IntelliSense nor compile the code.

image

image

Places Discards Are Applicable

  • A declaration expression with an out modifier, for example: bool.TryParse(“string”, out _)
  • Pattern matching clauses, such as case int _ or if (x is string _)
  • Deconstructions:
    • In declaration: such as var (a, _, c) = myObj
    • In assignment: such as var a, b; (a, b) = myObj
    • Value Tuple deconstructions: such as var (a, _, _) = (1, 2, 3)

The _ Keyword

Please always remember that the _ is a contextual keyword, like var, that means if you have already declared a local variable _ in the current context and it is in scope, the _ will not be a discard and will refer to that local variable in scope.

image

More interestingly, look the following code:

 bool _ = false, v = false;
if (bool.TryParse("TRUE", out var _))
{
     /* Do your stuff */
     v = _;
}

What is the value of v?

The answer is false. The if test is true, and string “TRUE” can parse as a Boolean value true, but we have out var _, this overrides the scope of the previously declared variable _, and it is a discard. Then the assignment v = _ inside if statement just reads the value of previously declared local variable _ (which is false,) and assigns to v, hence the value of v is false. If we remove the var to change the code to out _, the value of v will be true because _ is on longer a discard and it holds the value of the parsed Boolean.

Conclusion

The discards in C# enables a way to ignore some local variables, it is a design time feature, the local variable may still be required at runtime and compiler may also generate a name for it. Since the _ keyword is a contextual keyword, you need to set a code policy to avoid declaring local variables with the name _ to reduce confusions. This feature is compatible with previous versions of .NET platforms as it does not require a CLR change.