In C# (and VB), using statements contain an embedded statement (traditionally, a block statement) that contains the code that will be run before the resource is disposed.
When multiple resources require disposal, using statements are nested to accomplish this (though traditionally written at the same level of indentation)
using(var r = new Resource())
using(var s = new OtherResource())
{
}
This works well if all resources can be acquired at the same time, but this cannot always be done. The motivating example, in this case, is the traditional boilerplate for ADO.NET, in which the block scopes provide more noise than signal.
void foo()
{
using (var conn = new SqlConnection("..."))
using (var cmd = conn.CreateCommand())
{
connection.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// ...
}
}
}
}
For scenarios like this, explicitly providing block scope often feels like overkill. While it's important to dispose of the resources properly, the block scope containing the using is often sufficient enough.
I would like to propose the following syntax:
using
_local-variable-declaration_ ;
This would effectively be syntactic sugar for 'Place this local variable declaration in a using statement, and place all statements within the same block that follow this statement into the statement list of that using block'. Basically, the desired effect is the variable follows normal scoping rules, and as soon as the variable falls out of scope, the resource is disposed.
With this new syntax, we can now write the above example as:
void foo()
{
using var conn = new SqlConnection("...");
using var cmd = conn.CreateCommand();
connection.Open();
using var reader = cmd.ExecuteReader();
while (reader.Read())
{
// ...
}
}
Do you really think this is worth all the work involved?
Nice, I like this
This has been proposed before, but I can't find the issue so perhaps it was over on CodePlex. Either way, I also like this.
Combining using
with var
does seem a little weird since the variable would have to be assigned and then would remain readonly for the remainder of the method. Perhaps with val
/let
depending on how that proposal shakes out.
The using
keyword is naturally associated to IDisposable
, while val
feels more like struct, and let
sounds immutable to me.
var
is just a placeholder for type, despite being somewhat unfortunately/mistakenly felt like a variable.
So unless better keyword proposed, I would prefer using
for this time.
The using
keyword would be involved either way. let
or val
are being weighed as keywords for readonly locals, so the immutable connotation is appropriate given that you're not permitted to reassign a using
variable today nor should you be able to in this proposal.
paulomorgado: Personally, yes, I do. I have seen many cases where having explicit control over the Dispose point through a new block scope is unnecessary, and variable scope would have sufficed. I understand every feature starts at -100. I'm willing to try to make my case.
HaloFour: I agree the silent read-only nature of the variable assignment is a bit unfortunate, but I came to the same conclusion - it's a practice established already through the current using statement semantics, so my hope is that it could be justified as such.
Also - yes, to be clear, the variable assignment would be read-only. This is intended to have exactly the same semantics as the traditional 'using' statement, but just in the current block scope.
Here's the CodePlex proposal for reference: 544789
HaloFour: Thanks for the reference. I believe this proposal is identical to that one, yes. It looks like it never reached a conclusion there? If I'm reading that right, this could be considered the GitHub issue for it, then.
Oh the wonders if let
implied using when the underlying type is IDisposible
.
void foo()
{
let conn = new SqlConnection("...");
let cmd = conn.CreateCommand();
connection.Open();
let reader = cmd.ExecuteReader();
while (reader.Read())
{
// ...
}
// conn, cmd, and reader are disposed here
}
How would the proposed syntax work out in case the IDisposable
instance is not assigned to a variable? Since there is no variable that goes out of scope, at what moment will Dispose
be called?
using (new RuntimeDurationLogger(Console.Out))
{
// slow code
}
bkoelman: I should have been clearer here - this proposal only permits the form of the using construct where there is a variable declaration.
This is not intended as a replacement for the traditional using construct - merely a complement to it.
Or there could be a using <expression>;
form. There would be an implicit variable anyway (as there is today) and it would be disposed where it would have gone out of scope:
if (condition) {
using new RuntimeDurationLogger(Console.Out);
// do stuff here
// Dispose called here
}
HaloFour: This certainly could be done. I had omitted this support from the proposal because I could not think of a scenario needing it, and it felt strange to have code that might just say 'using myVar;' somewhere. But, it would simplify the proposal to do what you are saying here.
@HaloFour in the use-case you describe above, when do you envision the variable leaving scope and thus being disposed?
Personally, I would assume the using
would dispose the object as soon as the method/constructor (new RuntimeDurationLogger
in your example) returned.
@whoisj
the use-case you describe above, when do you envision the variable leaving scope and thus being disposed?
At the closing brace of the if
block. The behavior would be the same as if the expression were assigned to a variable. It would effectively convert into the following:
if (condition) {
using (new RuntimeDurationLogger(Console.Out)) {
// do stuff here
}
}
Personally, I would assume the
using
would dispose the object as soon as the method/constructor (new RuntimeDurationLogger
in your example) returned.
Wouldn't be much point in that, would there? Might as well just write new RuntimeDurationLogger(Console.Out).Dispose();
.
@HaloFour
What is the point of waiting for the closing of the if
block? I do not see how that is explicit in any way.
I was working off the assumption that using new RuntimeDurationLogger(Console.Out);
was equivalent to using (new RuntimeDurationLogger(Console.Out)) ;
. I do not think that I would be alone in that camp and thus this could cause much confusion.
@whoisj Because keeping the reference alive/undisposed within the scope is the purpose of that class? That's why using
blocks don't require variable declarations today. I don't think it's confusing, but that may be reason enough to avoid such a syntax. Variable scope is certainly easier to piggyback.
@HaloFour
let
is already a keyword in Linq, also readonly, but is not constrained/specially tweaked to work with IDisposable
, there are other proposals about immutable so maybe leave this keyword to them?
I think this proposal is about simplifying, making less indents, it's better keep it simple.
Well the different behavior between using ( blah );
and using blah;
surprise me though, but I wonder if anyone would create something and dispose immediately.
For what its worth:
using (var x = new X()) ;
emits a compiler warning today.using var x = new X() { /* ... */ }
would be a syntax error in this proposal.@diryboy I was referring to proposal #115 to introduce readonly
parameters and variables in which they explicitly mention a var
-like shorthand for inferred local variables using either let
or val
, although I do believe they were leaning towards val
. My mention has nothing to do with IDisposable
rather the fact that these variables would have to be readonly.
As mentioned by @rhencke the following code today already generates CS1656
C#
using ( var d = new Disposable() )
{
d = new Disposable();
}
So no need to emphases readonly in a simplified version IMO.
OK, @HaloFour I read your first comment again and understand what you meant, it's about combination, using var ..
and using val/let ..
are both good.
We could just get rid of the confusion altogether:
``` c#
using conn = new SqlConnection("...");
using cmd = conn.CreateCommand();
That would really just shorthand for whatever syntax is agreed upon (`using var` vs. `using val/let`), which would still be legal if writing it out explicitly is preferred.
I'd like to see removing the requirement for `var` in more cases where declaration is the only possibility. For example:
``` c#
foreach (result in results) { ... }
There is still be a good reason to allow declaring type as the class may have explicitly declared interface methods, or shadowed members that can only be called when cast to the appropriate type.
There is also some coding styles which prefer avoiding using var
at all cost. It's really a mixed bag thing, and I wouldn't want to force people to change their styles in the name of sugar.
As for the the using(SomeMethodThatReturnsIDisposable()){}
, it's not completely insane. Some times, the creating and disposing is all you want. Especially in the case of classes that abuse the using
.
@whoisj
Oh the wonders if let implied using when the underlying type is
IDisposible
.void foo() { let conn = new SqlConnection("..."); let cmd = conn.CreateCommand(); connection.Open(); let reader = cmd.ExecuteReader(); while (reader.Read()) { // ... } // conn, cmd, and reader are disposed here }
What if I have a SqlConnection
factory method? I light of what's being proposed for let
as readonly var
, this would be valid:
SqlConnection GetConnection(...)
{
let connection = mew SqlConnection(...):
// ...
return connection;
}
Under your suggestion, it would be returning a disposed connection.
@rhencke, some say -100 others say -1000.
What would you drop from what the team is proposing to work on in favor of this?
@paulomorgado: This was a reference to http://blogs.msdn.com/b/ericgu/archive/2004/01/12/57985.aspx.
Quite simply, I am not the right person to make decisions in that area. If you have objections to the proposal itself, I am happy to discuss them with you.
@mburbea, I'm not sure if your reply was to me, but just to be clear I am not suggesting to remove explicit type declarations. You would still be free to do that if you prefer (just as today you are free to use explicit type declarations instead of var
).
For the foreach
case some library still use the non-generic version of IEnumerable
, like System.Text.RegularExpressions.MatchCollection
, that case foreach ( Match m in matches )
is useful.
Allowing to omit type confuses autocomplete, as I mentioned this in #5050 for a similar syntax
@diryboy I'm not sure what someone would expect from autocomplete/intellisense at those points other than a type name. Autocomplete wouldn't suggest the name since it has not been declared yet. How is it ambiguous?
I like this proposal. It's similar to what I've proposed around the scoping for namespaces (#595).
As others have mentioned, let
doesn't need to be a part of it; as the using
variable is already readonly.
Can you make a topic on UserVoice and add a link for people to go vote on it (and vice versa)?
@MgSam: Sure - pardon my ignorance, but where would be the appropriate UserVoice for this?
@bondsbw Did you notice autocomplete has 2 modes?
When possible(and most of the time), VS allow one to commit the selected item from autocomplete list and also append the commit character using space or other characters like (, < and , etc.
So, for example when one want to write a method call to Abc
, he/she could just type a ( and get Abc(
, assuming Abc
was selected when he/she typed a. I call this mode aggressive mode.
But there is another mode, let's say this Abc
method accepts a Func<int, int>
as parameter, it's possible for the user to type the name of an existing function name Xyz
that accepts an int and returns an int, or a lambda expression x => ..
, in this case when user types x and space autocomplete will not replace x
with Xyz<space>
. This mode is known as suggestion mode.
Now consider this proposal with your suggestion, when the following 2 syntax are allowed:
using Abc = ...
using Abc Def = ...
When you type using
and space, autocomplete will have to fall in suggestion mode because Abc
could be a type or variable name, which I think it's a degrade of coding experience.
@rhencke
using var x = new X() { /* ... */ }
would be a syntax error in this proposal.
wouldn't that be object initialization (with the necessary semi of course)? Just have to consider http://ayende.com/blog/3810/avoid-object-initializers-the-using-statement
Perhaps there should be a warning when using statements and object initialization interacts (does X
become disposable when the constructor completes or when the object initialization finishes?).
@rhencke http://visualstudio.uservoice.com/
@bbarry This is true - however, even in that case, what is allowed in the /* ... */
blocks would be very different between using using var x = new X() { /* ... */ }
and using (var x = new X()) { /* ... */ }
. The former only accepts a comma-separated set of initializations, where the latter only accepts one or more semicolon-terminated statements. Off the top of my head, I can't think of any scenario where the same text would be accepted in both blocks.
Regarding when x
with an object initializer becomes disposable, I'm not sure. But I'd hope for the same semantics in both cases, whatever those semantics are.
@MgSam Per your request, I have created http://visualstudio.uservoice.com/forums/121579-visual-studio-2015/suggestions/10200273-create-a-using-local-variable-declaration-in-c.
@diryboy I get the difference between aggressive and suggestive, but typing using
space probably should not automatically insert anything. Perhaps using
spacespace would cause autocomplete to kick in, but if you were going for using Abc = ...
then you wouldn't type the second space that selects an item to autocomplete. Only if you want using Abc Def = ...
would you ever type using
spacespace, the second space selecting the top type in the autocomplete list.
So I think this is still unambiguous, and similarly other cases would be too (you wouldn't want foreach
( to automatically select something, you would want that to happen upon foreach
(space).
@bondsbw Typing using
(or probably only just us
) and space does not cause any additional thing except using<space>
typed in, but at this point the autocomplete list would show up, the ambiguity comes when you continue to type a space, what is result? Abc<space>
or just a<space>
?
The IDE will never smart enough to insert the actual Abc
you have in mind when you just type space space
Do you mean to have autocomplete list appear only when hitting the second space, without inserting the second space, and wait for user to select one and commit? This change of behavior works, but it's unintuitive for me at first. Because space is not an existing control character that is not expected to get inserted sometimes like ↦ or ↵.
But don't get me wrong, this suggestion is better than suggestion mode, because one have to move the hand further and press ↓ in suggestion mode to actually select something.
Well, for the foreach
case I always type foreach
followed by tabtab to insert the snippet, without typing ( or { myself. Maybe it's a bigger problem for those who prefer hand typing that and prefer a space within control flow parenthesis: foreach (<space>var m in ms )
@rhencke the semantic of how the using statement and how object initializers work are both very clear and straightforward but the interaction between them causes the refactoring of moving member assignment into an object initializer to not produce the same code:
using (var o = new ClassWithUnmanagedMemoryAllocatedInConstructor()) {
o.SomeProperty = MethodCallThatThrowsException();
//code that never executes
}
That is not a memory leak (provided o
correctly implements IDisposable
).
using (var o = new ClassWithUnmanagedMemoryAllocatedInConstructor {
SomeProperty = MethodCallThatThrowsException()
}) {
//code that never executes
}
That is. This refactoring is not equivalent code.
I would expect this form of using
to work the same way. The entire request here simply allows a level of nesting to be removed (which I think may be a worthwhile endeavor in itself) by changing the spec from
_declaration-statement_:
_local-variable-declaration_
_local-constant-declaration_
to
_declaration-statement_:
_using-local-variable-declaration_
_local-variable-declaration_
_local-constant-declaration__using-local-variable-declaration_:
using
_local-variable-declaration_
with the implied semantics that the statements following this declaration statement within the current scope are inside a using block to eventually dispose of the variable declared here.
@diryboy Up to this point I haven't tested what you were talking about, but I can't replicate the aggressive behavior you claim exists today by typing a(xspace. When I get to xspace, that doesn't perform any auto-completion. I've tried it in VS 2012 (both with and without Resharper) and VS 2015.
Regardless, I'm not opposed to having the behavior you mentioned as an option, but I personally don't like such aggressive autocompletion.
So, instead of throwing out the language idea completely because of a secondary IDE feature, how about make the IDE feature optional?
@bbarry I do see what you mean. It might be worth filing an issue on that behavior independent of this.
@bondsbw @diryboy If the variable type is omitted in the interactive C# REPL, the parsing becomes ambiguous. It could either be parsed as:
using alias = namespace;
or
using variable = expr;
@bondsbw Isn't that exactly what I've been described? When we have Abc( Func<int, int> f )
:
a(
and get Abc(
, aggressive modex<space>
and get Abc(x<space>
, suggestion mode@rhencke Good finding. Now we have another reason not to omit the type.
@diryboy Sorry, I misread, I thought you were saying that suggestion mode is insufficient. Suggestion mode would be fine.
@rhencke It would not be semantically ambiguous, because it is illegal to have the same full name for a class and a namespace.
@bondsbw I meant having some place forcing autocomplete to function in suggestion mode degrades the coding experience. But surely it depend on how the language feature justify.
One of the examples is why Linq expression was designed to start with from
rather than select
.
Before C#6 introduced expression bodies on method-like members, I have never thought about short one-line methods. I was surprised how many one-line methods exists.
Now I noticed that there is another often pattern in my codebase. One-line using.
public static bool HasPrivilege(this User user, int privilegeId)
{
using (var ctx = new DbEntities())
{
return ctx.UserPrivileges.Any(up => up.UserId == user.UserId && up.PrivilegeId == privilegeId);
}
}
using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
fs.Write(recordBlobDto.Bytes, 0, recordBlobDto.Bytes.Length);
}
This is not proposal. I would only like to know, could anyone this shorter notation 'new using' or 'using new' be useful?
public static bool HasPrivilege(this User user, int privilegeId) =>
new using DbEntities().UserPrivileges.Any(up => up.UserId == user.UserId && up.PrivilegeId == privilegeId);
new using FileStream(filePath, FileMode.Create, FileAccess.Write).Write(recordBlobDto.Bytes, 0, recordBlobDto.Bytes.Length);
@gordanr I'm not sure what you gain with that over something like (which works today)
public static bool HasPrivilege(this User user, int privilegeId)
=> using (var ctx = new DbEntities()) { return ctx.UserPrivileges.Any(up => up.UserId == user.UserId && up.PrivilegeId == privilegeId); }
It is more compact notation without "(var ctx = ) { return ctx }". It can be more readable, but I'm not sure is it worth to implement.
I don't say that it's an extraordinary idea. Just call for brainstorming. Maybe someone can generalize thing and get realy good idea looking at that.
@gordanr that is an interesting thought, if instead of a new _using-local-variable-declaration_ statement, there was a new _using-object-creation-expression_ ...
It sounds like something much more complex; anywhere you can declare a variable, you can inject disposable semantics?
{
var a = new using FluentClass(...).MethodReturnsSomethingElse(...);
var b = new using FluentClass(...).MethodReturnsThis(...);
}
Does the instance get disposed for a
immediately when the statement is complete? Where does b
get disposed?
{
DisposableClass d;
var x = new using DX(new using Y().Z);
x.TryGetD(out d);
} //how many things get disposed here? Where does Y get disposed?
hm
@gordanr That sounds like it would be more appropriate in the context of #5402 which seeks to have an expression form of using
.
Ya know, it sounds a lot like we're striving for a form of RAII here. :wink:
@whoisj The IDisposable
version of it, but basically yes.
@HaloFour
The IDisposable version of it, but basically yes.
That's the closest we're going to get with the CLR and GC they way they are today.
I would absolutely love a way to say "this variable is 'disposed' or 'collected' or what-have-you when it leaves scope". The using
statement is the closest we have today - extending its usage is ideal.
@whoisj: You caught me. :)
I would love to have this. Among other things it makes it easier to add a using
later because there is no need to add a new block.
Also, it would increase adoption of using
which many weaker developers are not properly using. A chronic problem in the .NET ecosystem.
This is a dup of #181 (admittedly this syntax is better).
Since we like this syntax better than #181, we'll track it using this issue.
Ya know, all of this comes down to C# having terrible ownership semantics. The introduction of a "borrowed" reference would likely resolve most of these issues.
(I now return you to your originally scheduled topic about using disposables)
just like deffer in golang, very good
I wish "fixed" statement could works similarly.
``` c#
fixed char* p1=&str1[0];
fixed char* p2=Foo(str2);
// blahblah...
```
Is there a separate proposal for doing this at class scope?
e.g. have this expand to have an automatically-implemented Dispose
method
class Example : IDisposable
{
using Stream _stream;
public Example(string path) {
_stream = File.OpenRead(path);
}
}
@Porges It was mentioned in other issue sometimes. I don't remember. But the main problem there is it must be readonly or else it might be replaced with another instance and the old one would not be disposed
@Thaina, good point. Perhaps if it were restricted to readonly
fields.
Should we be keeping the related discussion here: https://github.com/dotnet/csharplang/issues/114 ?
It would also be useful if fixed
statements worked in a similar manner (implicitly scoped to the containing block).
It would also be useful if fixed statements worked in a similar manner (implicitly scoped to the containing block).
Um...
fixed (char* pchar = m_value)
{
// do things with pointer.
}
Not sure I want the member m_value
being destroyed at the end of that fixed
statement.
@whoisj, I meant more of the perspective of being implicitly scoped, rather than being RAII. stackalloc
, at least based on the underlying IL instruction and the C# spec, does not allow explicit freeing of the memory.
The using
statement itself is essentially RAII already (lifetime starts at the beginning of the scope and ends at the closing of the scope), so this request is essentially just stating that the explicit scope declaration should be considered unnecessary and we should support it being implicitly determined by the compiler (this mostly just removes levels of nesting and makes code easier to read).
The fixed
statement doesn't really have anything to do with RAII, but does have the same issue that using
has, which this proposal is suggesting we fix (explicitly declaring blocks is tedious and makes code harder to read).
@tannergooding sounds to me, what you're really after is Rust-like ownership semantics. Me too, but it would predicate too many changes in the CLR to happen in any reasonable time frame.
@whoisj I think @tannergooding is talking about something like this:
{
fixed int* p = e;
// use p
}
which is equivalent to:
{
fixed (int* p = e)
{
// use p
}
}
@alrz gets it, I'm just bad at communicating sometimes 😄
I'm just bad at communicating sometimes
It is just as likely that I'm just dense and not understanding, but yup I get it now thanks to @alrz 😄
This is what I was looking for today.
My code is something like this:
List<MyResults> results;
using (var sheet = new MyExcelSheet(excelFilePath))
{
results = myExcelReader.ReadResults(sheet);
}
I would like to be able to shorten it to
var results = myExcelReader.ReadResults(using new MyExcelSheet(excelFilePath));
(MyExcelSheet
is a thin facade around EPPlus, implementing an interface so I can unit-test the Excel reader.) Note that in the long code, I need to give the explicit type of the variable results
, whereas in the short code, I can use var
.
@hoensr, where would be the start and end of the scope of that object?
Since the MyExcelSheet
is an anonymous variable, it would be like in C++: The scope ends at the semicolon.
I'm asking for the scope of the object. When will it be disposed?
Sorry to be unclear. At the semicolon, too. Anything else would be a surprise, wouldn't it?
Can you show in what that would be lowered to?
Sorry, I'm not sure I understand what you mean with "lowered to". My idea that these inline using
statements are equivalent to a using
block ending with the current statement. See the equivalent version in current syntax above.
@hoensr
Discussions regarding language design have moved over to the csharplang repository. This issue is a championed proposal and the conversation has continued here: https://github.com/dotnet/csharplang/issues/1174
@HaloFour : Thank you! I guess I will add my comment over there, then.
This is being done in C# 8.0. See https://github.com/dotnet/csharplang/issues/1174 for any further discussion.
Most helpful comment
Since we like this syntax better than #181, we'll track it using this issue.