-
Notifications
You must be signed in to change notification settings - Fork 1k
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can't use C# 8.0 using declaration with a discard #2235
Comments
@mavasani for the code fix bug |
We should probably just consider a using variable declaration as an effective read of the underlying variable, so the assigned value is not deemed as unused. I can send a PR for it tomorrow. |
Tagging @chsienki @AlekseyTs and @333fred. The false positive from the IDE unused value assignment analyzer is due to missing IOperation support and hence missing ControlFlowGraph support for using variable declarations #dotnet/roslyn/issues/32100. Analyzer is performing flow analysis on top of CFG to flag assignments whose target is never read or referenced. CFG for this code has a local variable declaration wrapped with an Operation.None and there is no subsequent local reference operation in the CFG. Implementing CFG support for this node would ensure there is an implicitly generated ILocalReferenceOperation for the compiler generated dispose invocation, which would remove the false positive from this analyzer and hence no suggestion to use discard would be offered. |
Actually, the analyzer/code fix to recommend using discard should be fixed in VS2019 Preview4 with |
Confirmed that unused value diagnostic + use discard code fix is offered in VS2019 Preview2 but not in latest VS2019 dogfood builds, and should be fixed in upcoming Preview4 release. |
@RayKoopa the new using declaration feature only works for explicit variable declarations, you can't apply Essentially using (var x = ...)
{
x.DoSomething();
} can be re-written as using var x = ...
x.DoSomething(); but using(SomeExpression())
{
} Can't be directly translated, as there's no declaration in the statement. You can however, assign it to a variable and it'll work, even if you don't use the variable for anything else. As you saw some of the tooling in the previews is a little out of sync with the newest language features at the moment, hence the unused diagnostic in VS, but the compiler will correctly track that it's actually used. |
Thanks for letting me know @chsienki! I noticed I can even go as far as using var _ = ... to "pseudo" discard the variable here, and it would still compile. That's really sufficient, just wanted to make sure it was done on purpose like this and is not something like an oversight. |
This would be quite useful. I'd love to be able to use using declarations with discards. |
There is also the problem of multiple discards. For now the only way is to add more underscores (actually giving different names to the variables as they are not really discards):
|
This could be useful for RAII-style lock acquisition; for example, one would be able to do void M()
{
using _ = myLock.Acquire() // rest of scope is protected by lock
// ...
} instead of having to implement something like #2451. |
This also makes it painful to use var foo = new Foo(); // Foo : IAsyncDisposable
await using var unused1 = foo.ConfigureAwait(false);
// ... In order to avoid declaring unused variables, you must go back to a var foo = new Foo(); // Foo : IAsyncDisposable
await using (foo.ConfigureAwait(false))
{
// ...
} |
What about this syntax for discarding the value? using myLock.Acquire();
// lock-protected code
// Also, don't forget about IAsyncDisposable!
await using myLock.AcquireAsync(); |
@TehPers, the problem is that: using (myLock.Acquire()); is already valid C# code and means something slightly different. Namely dispose the resource right now and not at the end of the outer block. |
up |
Our use case for this is Serilog's
instead of:
|
I'm interested in championing this. It's an annoying inconsistency that I've wanted to fix for a while now. |
@333fred I thought this was an open question, but @jcouv pointed out we already approved in LDM (dotnet/roslyn#43292 (comment)) |
Well, we still need to triage it. I imagine we'll put it in any time, but we need to decide. |
Since there is no language issue, I'll go ahead and close the csharplang issue. We'll track the bug fix with roslyn issue (dotnet/roslyn#43292). Thanks |
This is still a language issue. |
Sorry, confused this with |
Technically it is possible to allow this: using var _ = ...;
using var _ = ...; The result would be similar to how the lambda function That said, the following would be more consistent with discards in general: using _ = ...;
using _ = ...; This was also not valid code in the past, but could become valid code in the future. |
We can change this. Code that is in error today can be made legal in the future :-) |
@TahirAhmadov They were talking about two
@sharwell But this is already valid code today ( |
Surely there are plenty of situations in the language already where what's legal or not depends on the context, including quite a lot of special cases about when Would it be so terrible if the standalone version of disposable- |
I would consider that terrible. |
Care to elaborate? I can't think of a good reason why you'd want one in a top-level statement context. Edited to add: to me, a rule that "disposable- |
I think |
|
oof... completely out of curiosity (because I know there's no going back), how much easier would this be to resolve if we didn't have top-level statements? |
Oh god, you're right....... 🙈 Why did anyone ever think it would be a good idea to allow a single underscore as a variable name? 🙈😅 But yeah, that's of course enough of reason, that it won't work.
I guess it'd be so easy that it even would have been implemented by now. Because usings inside methods (or similar scoped members) do not pose any ambiguity as far as I know. Considering this topic I'm kind of surprised there aren't more problems with top-level statements. Nonetheless: |
My humble based on no data whatsoever opinion: |
I simply to |
There would be no conflict at that point. But it would also prevent local using aliases if we ever wanted that. |
I think the concern over top-level statements is not justified. First off, using clauses must be at the top of the file. The following fails with CS1529:
So the only time there is any ambiguity is when a using expression with discard is desired as the very first line of the top-level code (after the usings). C# already handles situations where the code is ambiguous. This should be no different. I would be perfectly happy with being required to clarify the code by using the old-school That said, I haven't been able to figure out any way to make it so that an identifier in the form So there is potentially no ambiguity at all. Can anyone think of a way to get something like |
From my understanding, it's not that it's impossible to resolve the apparent ambiguity (and even if a usage does happen to be ambiguous somehow, I think there's a general understanding that an error would be fine). Rather, as I understand it, the issue here is that because a statement at the top of a file of the form So (again, as I understand it) if this were the kind of feature that would REALLY add a lot of value, then I'm sure the team would be able to overcome the issues and get something that works just perfectly (which is why I imagine this hasn't been outright closed as "rejected"). As the problem it solves is really just a minor inconvenience in the grand scheme of things, however, I'm not surprised that it has taken this long without a resolution. |
While I understand and applaud the push to reduce unnecessary ceremony, fixing this would improve my developer experience far more than top-level statements ever will. |
Probably a non starter, but changing the namespace using to |
Yes. That would be a non-starter. That would also introduce its own set of issues as things like |
Agreed, besides being next to useless for experienced developers, top level statements are already an ugly hack and come with a huge list of caveats which need to be considered when programming in that context. I don't think adding yet another caveat to that list of pitfalls will be much of an issue, for a feature that is hugely useful in actual real-life code. |
Let's introduce the |
I agree, allowing One option for the top-level statement problem might be to simply disallow them. It's not like anyone uses them in any realistic scenario 😀 Realiztically, we can just disallow The breaking change itself is not going to change the meaning of anyone's code apart from preventing it from compliing, unless they both used top-levels and an underscore alias, presumably vanishingly rare. |
Nah, the new keyword should clearly be "notusing" |
Hopefully the new breaking change warning proposal could allow us to sort this out once and for all. We should either enable: using GetSomeDisposable(); (which currently, if there are parentheses around the expression, could mean this) using _ = GetSomeDisposable(); (which currently could be a type alias) The former is actually the ideal one; it would be perfect. |
I think both should be available, in case the local rules allow unassigned object, and do not force the discard notation for non-used return values. |
I like your thinking. Technically it is used as you say. I prefer the
After 10 months, I've finally stopped laughing at this statement. I love top level statements: they are one of the best features added to the language in recent years. But there again I wrote my first line of code only 42 years ago, so I guess I don't yet qualify as experienced 🤣 |
What does a "used return value" mean? |
I mean, it is a warning (maybe from resharper), when you call a method, but do not use the return value for anything
this does not:
|
Is it really a problem that we have an ambiguity in top-level statements? using System;
using System.Collections.Generic;
Console.WriteLine("Beginning using");
using MyResource();
Console.WriteLine("Terminating using");
IDisposable MyResource()
{
return null; // maybe something not null
} Using the block using statement will surely solve this problem. It will be clearer that the Alternatively, if we want a universal solution that also covers top-level statements, I think that indicating that this is a using statement on an expression, we could adopt something like using var MyResource();
using var x = AnotherResource(); The justification is that uninitialized variable declarations are not allowed in a scope-wide using statement. This
|
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
C# 8.0 adds the possibility to declare using variables without a corresponding using block, discarding the variable as soon as the scope in which it was declared is left.
The official example shows it with assigning the using variable to an actually named variable as you would typically do:
However, this does not seem to work if I don't actually need the variable being disposed. My use case is a temporary
Seek
object which remembers the current position in a stream when created, and reverts to that position upon being disposed. It is used like this:I tried to rewrite this in C# 8.0:
However, this yields CS0118 'reader' is a variable but is used like a type. A bit stumped here already, I then tried storing the
Seek
instance in a discard variable at least:But this now yields CS0246 The type or namespace name '_' could not be found (are you missing a blahblahblah...?). More stumped, I then became even more explicit:
While this compiles, it feels very odd to me. Jokes on Visual Studio 2019 trying to break my code now too and forgetting to use
using
at all:Is this a known issue, done on purpose, or an oversight in the feature?
The text was updated successfully, but these errors were encountered: