Is there a difference between using discard or ignoring the value returned by a method?

Asked

Viewed 113 times

7

I have a method similar to the below:

public bool FazerAlgoERetornarSeSucesso() => true;

And at some point, I need to call this method, but I don’t care about the result. Normally I would do something like:

FazerAlgoERetornarSeSucesso();

However, in C# it is possible to use discards. In this case, the code would look like this:

_ = FazerAlgoERetornarSeSucesso();

In addition to legibility being impaired, there is some difference between using discard and simply ignore the return value of the method?

1 answer

3


I would say that legibility is improved, at least from a certain point of view, it can be subjective.

The second way is more explicit and this has its legibility advantage, although one can say that code that does nothing useful is noise and then yes would be less readable, depends on the school that you use to define what is readable.

Just remember that C# has never forbidden you to silently discard a function call result. Some languages only let you discard the result explicitly, otherwise you have to use the result in an expression, including storing it in a variable. Now C# lets you be explicit in the discard, but still accepts to be implicit.

And C# makes no mistake or Warning by not using a variable, then also does not exist so, and the specific case neither involves a variable that would be mandatory without the discard.

So one benefit is being more explicit and becoming more readable.

I figured it out by reading a Eric Lippert’s simple answer that C# has no obligation to optimize this, but can, he cites Haskell who has an obligation not to even calculate. But note that this is not about the discard, because it could do even without his presence since the result is not really used. But Haskell is a pure language, C# is not and this optimization would be more complicated, even more if done by Jitter since it would be something that would take time to identify whether you can optimize or not, and this done at runtime can defeat the possible benefit it would bring. In C# the functions can have side effects, and an optimization of not performing the function because the result can be discarded can fail to do something internal that will affect other parts.

In another answer on Soen no one disputes that it is useless in this scenario. It would be the same as not using the discard.

But I will disagree on one small point. It may be that today is like this, I do not know if later, officially or not, if the language does not do some optimization that it would not do without the discard. Then you have to think about whether it’s worth it or not. So I would take Eric Lippert’s advice, use if you think the code will be more readable, not if it gets faster, unless you need a lot of performance and measure in the implementation of the moment whether there’s an advantage or not, which is worth today may not be worth more in the past. I’ve seen a lot of things change without anyone warning, some for the better and some for the worse.

The disposal was not created for this

And reading also the documentation it becomes clearer that the utility is even where a variable would be needed for some reason, not the example reported in the question here that the variable is not needed.

Documentation shows a situation that can make a difference if you are returning a Task, then it is a case that you cannot ignore the result without being explicit. But it is not the case for your example.

And the documentation also shows that it can be a problem because _ can be a valid variable name and then this function takes precedence over the specific language construction, even for compatibility reasons. But you have to congratulate those who used it as a variable name.

In fact the mechanism was created to improve this point with Pattern matching, tuples (deconstruction) and even with the good old output parameter out, it was not thought for other situations, but it would not make sense to prohibit a "deconstruction" of a method that returns a simple value, so the syntax has allowed its use for the sake of parity with the rest.

All this since C# 7. What C# 9 has brought is parity for Amble that I used to not let use and was weird, including in lambda makes even more sense, has situation where it could require a variable.

Creating a variable and keeping an object alive in it needlessly has bad consequences, but that may not be a problem, although it would be better not to have the variable, but the case is not a choice between having a variable or not. The answers I read show cases that make a difference in other scenarios, which makes perfect sense.

If you were buying:

var objeto = FazerAlgoERetornarSeSucesso();

and did not use objeto nowhere, and

_ = FazerAlgoERetornarSeSucesso();

The second is clearly better because it avoids an accidental use of `object in future maintenance (as discussed in chat :P), and of course creates a variable that reserves space in the stack and secures the returned object for longer, but

FazerAlgoERetornarSeSucesso();

gives, today, in the same, internally.

Completion

So I’m going to nail that in this scenario, until someone proves otherwise that there is no advantage beyond subjective legibility, there is no difference.

There will be no less memory allocation, no less pressure on the GC or even less stack reserve comparing the two cases because both do not exist variables. What has changed in C# 7 is that _ is not a variable more, before if you used that symbol was a variable with that name (provided that declared with a type or var) and without optimization it would need to be reserved. But the returned object changes nothing.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.