18

In c# 7.0, you can use discards. What is the difference between using a discard and simply not assigning a variable?

public List<string> DoSomething(List<string> aList)
{ 
//does something and return the same list
}
_ = DoSomething(myList);
DoSomething(myList);

Is there any difference?

Wojtek322
  • 584
  • 7
  • 20
  • 1
    Almost certainly no difference. In this example the language already provided a way to not use a variable. The discards real value is in all the cases where typically a variable would be required even if its not needed. Like pattern matching one element of a tuple but not the other, for example. – Michael Welch Oct 24 '20 at 15:06

3 Answers3

20

There's absolutely no difference between the two code lines.
Both of them translate to exactly the same IL:

public void A(List<string> myList)
{
    _ = DoSomething(myList);
}

public void B(List<string> myList)
{
    DoSomething(myList);
}

Both translate to:

IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: call instance class [System.Private.CoreLib]System.Collections.Generic.List`1<string> C::DoSomething(class [System.Private.CoreLib]System.Collections.Generic.List`1<string>)
IL_0007: pop
IL_0008: ret

You can see it yourself on SharpLab
(Note: I can't actually read IL, but this is the result of both A and B methods)

Discards are useful, as Liam wrote in his answer, for out parameters you're not going to use, for tuple deconstructions, for pattern matching, and for switch expressions.
You can read all about it in the official documentation.

Update following Liam's comment: Please note that I'm only referring to this specific scenario.
When used as intended, discards are memory-efficient and/or improve the readability of your code.

Boann
  • 48,794
  • 16
  • 117
  • 146
Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
8

Discards are more for out parameters that you don't care about. For example:

if (int.TryParse(123, out _))
{
   ....
}

They really only exist to prevent you having to declare a variable that you don't use. So the old way of doing above would be to do:

int throwAway;
if (int.TryParse(123, out throwAway))
{
   ....
}

To quote the docs:

Because there is only a single discard variable, and that variable may not even be allocated storage, discards can reduce memory allocations. Because they make the intent of your code clear, they enhance its readability and maintainability.

So discards are memory-efficient (though this depends on usage) (don't do this as an optimisation; IMO this very much falls into the area of premature optimisation, as the efficiency gain is tiny) but more importantly they make your code more readable by making it obvious that you don't intend to do anything with the variable.

Boann
  • 48,794
  • 16
  • 117
  • 146
Liam
  • 27,717
  • 28
  • 128
  • 190
  • It's probably better to use a regex if you just want to test whether a string is a number. Though I'm not commenting on your answer as much as I'm just commenting on the use case from the docs. – Captain Kenpachi Oct 13 '20 at 08:31
  • 4
    @CaptainKenpachi better in what way? using a regular expression will probably cost more in terms of memory usage, and don't get me started on code readability. Don't forget that this `-3.14e3` is a valid integer. [Check out this SO post](https://stackoverflow.com/questions/9043551/regex-that-matches-integers-only) – Zohar Peled Oct 13 '20 at 08:34
  • You'd be surprised what goes on under the hood of .TryParse. https://stackoverflow.com/questions/15294878/how-the-int-tryparse-actually-works – Captain Kenpachi Oct 13 '20 at 08:39
  • 2
    TBH I'd choose Regex vs try parse based on readability rather than optimisation. Based on [premature optimisation being the root of all bad things and all](https://softwareengineering.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil) – Liam Oct 13 '20 at 08:45
  • 3
    @CaptainKenpachi The fact that int.TryParse doesn't use regular expressions should indicate that it's probably better to not use a regular expression. I don't really care enough to conduct performance tests, and I totally agree with Liam's comment. I'd choose readability over performance any time, except when writing performance-critical code - and even then - I'd start with a readable code and work my way from there to improve it's performance if needed. – Zohar Peled Oct 13 '20 at 08:53
2

Following two lines don't have a difference at compile level.

_ = foo();
foo();

Subtle difference in IDE level: foo(); can show a warning in Visual Studio later than 2019, because you didn't use return value of a function.

According to MSDN,

discards can reduce memory allocations. Because they make the intent of your code clear, they enhance its readability and maintainability.

Reference: https://learn.microsoft.com/en-us/dotnet/csharp/discards

Following link might also help.

it seems that the discards have a higher sinergy with other paradigms introduced in the most recent versions of C# like tuples deconstruction.

Reference: Discard feature significance in C# 7.0?

Se-woong Lee
  • 29
  • 1
  • 5