Skip to content
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

Champion "Implicitly scoped using statement" (16.3, Core 3) #1174

Open
2 of 5 tasks
gafter opened this issue Dec 6, 2017 · 107 comments
Open
2 of 5 tasks

Champion "Implicitly scoped using statement" (16.3, Core 3) #1174

gafter opened this issue Dec 6, 2017 · 107 comments
Assignees
Labels
Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification Proposal champion Proposal
Milestone

Comments

@gafter
Copy link
Member

gafter commented Dec 6, 2017

This is for some form of using statement, where the statements executed while the resource is held are the following statements in the same block that contains the using statement; the resource is freed at the end of the block.

See #114 and #114 (comment)

LDM history:

@DavidArno
Copy link

DavidArno commented Dec 7, 2017

Downvote retracted. It was based on a misunderstanding on my part, over both how the current syntax works and a misreading of the new syntax.

Downvoting this. I didn't see the need for it when @HaloFour first proposed it, and I don't see a need now.

This is a "saving a few characters and a bit of indentation" proposal that makes the code harder to read as the usings have no obvious scope and just "magically" disappear at the end of the method. And since we now have local functions, there's even less need for it. Taken the original code example, it can already be expressed as:

public void Foo()
{
    using (var connection = OpenConnection(new SqlConnection(connectionString)))
    using (var command = SetupCommand(connection.CreateCommand()))
    using (var reader = command.ExecuteReader())
    {
        while (reader.Read())
        {
            ProcessRecord(reader);
        }
    }

    SqlConnection OpenConnection(SqlConnection connection)
    {
        connection.Open();
        return connection;
    }

    SqlCommand SetupCommand(SqlCommand command)
    {
        command.CommandText = "SELECT FOO FROM BAR";
        return command;
    }
}

In my view, in the above code it is immediately apparent as to the scope of the using blocks, which the proposal in #114 lacks.

@HaloFour
Copy link
Contributor

HaloFour commented Dec 7, 2017

@DavidArno

That instantly doubles the length of the method. Sure, it works, and sure, it avoids indentation, but at the cost of much unnecessary verbosity.

The scope of variables within a block is already a well defined concept in C#. There's no more "magick" here than should be obvious and expected.

@mikedn
Copy link

mikedn commented Dec 7, 2017

the usings have no obvious scope and just "magically" disappear at the end of the method

They do not disappear at the end of the method, they disappear at the end of the scope the variable was declared in. That's natural, there's nothing magic about it.

In fact it can be argued that the current using makes no sense because it forces you to create a new scope for no reason. Though it's sometimes useful when you need the using scope to be smaller than an already existing scope. When this happens in C++ what people do is create e block just for that:

void foo()
{
    {
        ObjX x;
       // use x...
    } // destroy x

    // some other code which does not need x
}

It's a bit weird but in my experience this need does arise too often.

@gulshan
Copy link

gulshan commented Dec 7, 2017

Kotlin has apply and also functions in its stdlib, which perform an action on a object and returns it. With them the code can be like-

public void Foo()
{
    using (var connection = new SqlConnection(connectionString).Apply(c => { c.Open; }))
    using (var command = connection.CreateCommand()
                          .Apply(c => { c.CommandText = "SELECT FOO FROM BAR"; }))
    using (var reader = command.ExecuteReader())
    {
        while (reader.Read())
        {
            ProcessRecord(reader);
        }
    }
}

@DavidArno
Copy link

@mikedn,

They do not disappear at the end of the method, they disappear at the end of the scope the variable was declared in.

Oh, that would be nasty. That suddenly brings all the issues around ; that C suffers from with while etc when a ; is accidentally placed after it:

using (var connection = OpenConnection(new SqlConnection(connectionString)))
using (var command = SetupCommand(connection.CreateCommand()));  // <- semicolon here
using (var reader = command.ExecuteReader())	// won't compile;command is now out of scope

@HaloFour,

... but at the cost of much unnecessary verbosity.

Clarity is never unnecessary verbosity. As you have pointed out to me on a number of occasions, it's never worth saving a few lines of code if the result is less clarity.

@HaloFour
Copy link
Contributor

HaloFour commented Dec 7, 2017

@DavidArno

Oh, that would be nasty. That suddenly brings all the issues around ; that C suffers from with while etc when a ; is accidentally placed after it:

Finding a syntax which better differentiates between the two forms would be a part of the design process. I agree that the feature should be made resilient to those kinds of issues. The syntax I've suggested is illustrative only.

Clarity is never unnecessary verbosity. As you have pointed out to me on a number of occasions, it's never worth saving a few lines of code if the result is less clarity.

Clarity is very subjective. The C# language does not require defining scope for every declared variable and it's pretty clear that the scope is inherited from the current block. In many non-GC languages a deterministic destruction/disposal when a variable goes out of scope is very common.

@mikedn
Copy link

mikedn commented Dec 7, 2017

Oh, that would be nasty. That suddenly brings all the issues around ; that C suffers from with while etc when a ; is accidentally placed after it:

I do not understand your example and the C "issue" it is supposed to illustrate.

@DavidArno
Copy link

@mikedn,

using (var connection = OpenConnection(new SqlConnection(connectionString)))
using (var command = SetupCommand(connection.CreateCommand()))
using (var reader = command.ExecuteReader())
DoSomething(reader);

is equivalent to:

using (var connection = OpenConnection(new SqlConnection(connectionString)))
{
    using (var command = SetupCommand(connection.CreateCommand()))
    {
        using (var reader = command.ExecuteReader())
        {
            DoSomething(reader);
        }
    }
}

So if changed to:

using (var connection = OpenConnection(new SqlConnection(connectionString)))
using (var command = SetupCommand(connection.CreateCommand())); // <- add semicolon
using (var reader = command.ExecuteReader())
DoSomething(reader);

It becomes equivalent to:

using (var connection = OpenConnection(new SqlConnection(connectionString)))
{
    using (var command = SetupCommand(connection.CreateCommand())) {}
}
using (var reader = command.ExecuteReader()) // command is out of scope here
{
    DoSomething(reader);
}

Adding or removing a ; would completely change the implied block structure of the code, leading to at least hard to figure out compiler errors, if not runtime errors.

This same problem used to plague me when writing C. Accidentally put a semicolon in the wrong place and things would go wrong:

while (true); // <- semicolon here
{
    // this block is unrelated to the while and is unreachable
}

@mikedn
Copy link

mikedn commented Dec 7, 2017

Hmm?!

using (var connection = OpenConnection(new SqlConnection(connectionString)))
using (var command = SetupCommand(connection.CreateCommand())); // <- add semicolon
using (var reader = command.ExecuteReader())
DoSomething(reader);

That's not how it's supposed to look like if this proposal is implemented. It's supposed to look like

using var connection = OpenConnection(new SqlConnection(connectionString));
using var command = SetupCommand(connection.CreateCommand());
using var reader = command.ExecuteReader();
DoSomething(reader);

The semicolon is required, like for every other variable declaration.

@HaloFour
Copy link
Contributor

HaloFour commented Dec 7, 2017

@DavidArno

It sounds like you're arguing against the current syntax of using, for which I'm afraid you're a little too late.

This proposal wouldn't have the same issue because the scope would not be tied to an embedded statement immediately following the statement. However, there is valid concern that the syntax I've suggested is too similar to the existing syntax since the only difference is the lack of parenthesis and the requirement of a semicolon. That's why @TyOverby suggested a different syntax employing a new keyword, using scope.

@DavidArno
Copy link

DavidArno commented Dec 7, 2017

@HaloFour,

I had mistakenly thought that using ((var x = new Disposable())) was valid and thus that () could still be wrapped around your new syntax. This isn't the case. So that removes my fear over random ; affecting things. 😊

using scope or some such would help to distinguish them better though.

@alrz
Copy link
Member

alrz commented Dec 7, 2017

sequence expressions + with clause?

using (var connection = new SqlConnection(connectionString))
using (var command = (connection.Open(); connection.CreateCommand() with { CommandText = sql }))
using (var reader = command.ExecuteReader())
{ .. }

oh no.

@MkazemAkhgary
Copy link

MkazemAkhgary commented Dec 7, 2017

could using be applied to assignment only?

SqlConnection connection;
using connection = new ...; // connection becomes readonly afterwards

if not, then declaration could be implied by one keyword so instead of using var you type using and that declares new variable. so using x = ... would actually declare read only x. I'm not proposing this though.

@ygc369
Copy link

ygc369 commented Dec 8, 2017

@HaloFour @gafter
Is this similar to #121?

@ghord
Copy link

ghord commented Dec 8, 2017

Following code does not compile right now:

    goto asdf;
    using (File.Open("test", FileMode.Open))
    {
        asdf:;
    }

With CS0159: No such label 'asdf' within the scope of the goto statement.

I guess

    goto asdf;
    using File.Open("test");
    asdf:;

Should be disallowed too.

@mikedn
Copy link

mikedn commented Dec 8, 2017

using File.Open("test"); doesn't make sense in this context, it should be a variable declaration. So the question is what to do about:

goto asdf;
using var file = File.Open("test");
asdf:;

If code after asdf is trying to use file then you'd get a Use of unassigned variable error so it's all good probably.

@ghord
Copy link

ghord commented Dec 8, 2017

@mikedn Yet there are cases where using statement without variable declaration makes sense. I don't see why single-line using without variable declaration should be disallowed.

@mikedn
Copy link

mikedn commented Dec 8, 2017

Yet there are cases where using statement without variable declaration makes sense. I don't see why single-line using without variable declaration should be disallowed.

Well, it is useful sometimes but IMO not often enough to warrant supporting this syntax. Besides, it seems natural to extend scoping so that "at the end of a scope objects stored in "using" variables declared in that scope are disposed". It's not so clear what's going on with using File.Open as there's no variable associated with it and thus it doesn't have anything obvious to do with scoping.

Perhaps using var _ = File.Open("test"); would be sufficient?

@ghord
Copy link

ghord commented Dec 8, 2017

Personally, code like this makes this feature most appealing to me. Previously, you had to introduce complicated scopes. Don't even get me started on mixing try and catch here - that would be another scope.

   void Method()
   {
       logger.Log("Text");
       using logger.Indent();
       ...
       logger.Log("Indented text");
       ...
       using logger.Indent();
       ...
       logger.Log("Twice-indented text");
       ...
    }

Adding var _ everywhere would look even worse than normal scoped using.

@MkazemAkhgary
Copy link

Yet there are cases where using statement without variable declaration makes sense

use normal syntax in that case. using var _ = is very agonizing.

@mikedn
Copy link

mikedn commented Dec 8, 2017

Personally, code like this makes this feature most appealing to me. Previously, you had to introduce complicated scopes. Don't even get me started on mixing try and catch here - that would be another scope.

Ha ha, it makes sense in your example. Though personally I'm still not convinced about its usefulness. Perhaps that's because last time I encountered code with so much logging ceremony I did something that I considered to be immensely useful in making the code more readable - I deleted it all 😁.

@MkazemAkhgary
Copy link

@ghord I don't know what library you are using, but is there any method like Indent(int count) ? in that case you can prevent nested blocks.

by the way designers had in mind to make indentation implicit using this trick. I'm pretty sure if this syntax (single line using) was possible on time they developed it, they would've thought of something better to overcome with that issue.

so really they wanted to take advantage of blocks and make indentation implicit, but you want to also omit blocks.

@alrz
Copy link
Member

alrz commented Dec 8, 2017

Re: using x = ... syntax, and generally using expression;

I want to mention #218 which may want to use the exact same syntax (if ever happens). On the other hand, using var x = ... (or using scoped for that matter), is not ambiguous with that syntax.

Though the result might be confusing, so perhaps using scoped is a better choice here.

@gulshan
Copy link

gulshan commented Dec 8, 2017

if a new keyword scoped is introduced, why not just use that without using? That will reduce confusion I think.

public static void CopyFile(string from, string into) 
{
    scoped var fromFile = File.Open(from, FileMode.Open, FileAccess.Read);
    scoped var toFile = File.Open(into, FileMode.Create, FileAccess.Write);
    // ... Perform actual file copy

    // Both FileStream objects are disposed at the end of the enclosing scope, 
    // in this case, the method declaration.
}

@TyOverby
Copy link

TyOverby commented Dec 8, 2017

@gulshan: by piggybacking off of the using keyword, it is way easier to amend the grammar.

@TonyValenti
Copy link

I think I would rather see C# keep track of whether a disposable object has leaked its scope and if it hasn't, have it automatically dispose it.

@VisualMelon
Copy link

VisualMelon commented Dec 10, 2017

@TonyValenti that isn't feasible/dependable: an IDisposable may be passed to another method which can do anything it likes with it. Some concept of 'ownership' would be required for that kind of analysis to work at compile time. (In a way, using says I own this, I'll deal with it, but it doesn't stop others trying to deal with it first)

@CyrusNajmabadi
Copy link
Member

I've seen Linq banned

And yet, Linq was still good to do. The presence of companies willing to ban over language features does not mean those language features should not be done. After all, i'm sure for every language feature, you could find some codebase that has banned it. But we obviously still work on new language features despite that.

@CyrusNajmabadi
Copy link
Member

I get the concern about the lifespan of disposable objects potentially lasting longer than necessary. This is particularly potentially egregious in async methods and iterators where the lifespan of the coroutine could be longer than your typical method call. These same concerns exist today with using blocks and the language does nothing to prevent you from making bad choices.

Indeed, i made this very mistake in Roslyn in the Sqlite layer. I made an async call while a disposable resource was being held. Should we ban async+disposal+usings? No. We just need to be careful when combining these things.

@popcatalin81
Copy link

Indeed, i made this very mistake in Roslyn in the Sqlite layer. I made an async call while a disposable resource was being held. Should we ban async+disposal+usings? No. We just need to be careful when combining these things.

That's exactly the point I was trying to make: It's too easy to combine using var with async. Thea feature almost facilitates combining them.

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented Oct 1, 2018

That's exactly the point I was trying to make: It's too easy to combine using var with async. Thea feature almost facilitates combining them.

So... the don't combine them. I mean, we do this all the time in other arenas. in places where allocation costs are problematic, we don't allow allocation-heavy features. In places where dispatch costs are problematic, we don't use virtual/interface dispatch. etc. etc. Not every language feature is appropriate in every codebase (or at any point in any particular codebase).

We have rules all over hte place for things you should be careful of because they might cause a problem. As i pointed out, async+disposal is already a problem, and it doesn't seem to be any worse here. In both cases you have to think about what's going on and set things up properly. So nothing really changes.

As i pointed out, not having "using var" didn't save me. The problem exists independently of the new language construct.

@popcatalin81
Copy link

popcatalin81 commented Oct 3, 2018

So... the don't combine them.

Don't worry I won't do it myself.

But I'll the one called to fix weird bugs because some dev has used a feature without understanding the semantics. But that's not a problem really. I'm a consultant, I make money when others screw up ... (That's why I'm skeptic about this feature, perhaps even biased)

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented Oct 3, 2018

But I'll the one called to fix weird bugs because some dev has used a feature without understanding the semantics.

That's an issue with all language features :)

Don't understand 'async'? Then you're going to have weird bugs. Don't understand lambdas, or generics, or 'ref', or operators, or structs, or inheritance, or stacks, or memory, or etc. etc. etc.? Then you're going to have weird bugs. We don't stop moving the language forward just because people there exist people who use the language without spending hte time to understand what's going on. :)

Heck, if you don't understand 'using' today, you're going to have issues. But life moves on and the language still improves so that people who do learn and understand can have a better experience :)

@popcatalin81
Copy link

That's an issue with all language features. Don't understand 'async'? Then you're going to have weird bugs.

Yes. But in this case, there simply is a better option: using block, using var is a simply a worse version of that, except syntax ... maybe ...

@Thaina
Copy link

Thaina commented Oct 4, 2018

@popcatalin81 Wrapping the whole function with using block into multiple of stacking pyramid is not better option. It not convenient and mess the code. Taking more time and energy to understand the code. While implicit using treat the disposing like it was a struct, just dispose when the stack pop out. Use it when we don't need to care just to ensuring disposal. And not affect the whole code like using block

@jnm2
Copy link
Contributor

jnm2 commented Oct 4, 2018

multiple of stacking pyramid

The usual phrase is https://en.wikipedia.org/wiki/Pyramid_of_doom_(programming)

@popcatalin81
Copy link

popcatalin81 commented Oct 4, 2018

@popcatalin81 Wrapping the whole function with using block into multiple of stacking pyramid is not better option.

@Thaina so you prefer a hidden Pyramid? opposed to a visible one? It's easier to understand an implied pyramid than an explicit one?

using var does not eliminate the pyramid it just hides it. But if you want it eliminated syntactically, using block already has this option, because you don't need to add brackets for each statement.

So let's see:

using block

  • Controlled nesting. (Can have un-nested using blocks in a single method)
  • Creates a scope for variables (Better analysis of lifetime)
  • Pyramid code can be avoided for nested usings by omititing braces

using var

  • Uncontrolled nesting. All declarations are nested at parent scope level. Un-nested using blocks in same scope are not posible.
  • Does not create a scope but uses the parent scope. Parent scope can be extended by adding more calls or code, which automatically prolongs disposable resource lifetime. It createa a dependency between method length, number of calls number of disposable resources, async calls, all affect each other negativelly.
  • Pyramid code does not exist at syntax level but there's a single giant piramid at logical level.
  • Potentially creates a dependency between variable declaration order. Switching variable declaration order now becomes an breaking change.

@Thaina
Copy link

Thaina commented Oct 4, 2018

@popcatalin81 It just a perspective. If you call it hidden pyramid then async/await is already one. It actually a callback pyramid that was flatten out by keyword

In my perspective it not a hidden pyramid because you shove all responsible stack to the parent scope. In intuitively the same as struct allocation on stack. It flatten out the all the pyramid into scope and having the same place to dispose, at the end of scope, and just in reverse order, which it should

It like you have array as stack. You don't need to really stack things in memory, it just abstraction to the LIFO process. And this make consistency for both code and memory

Hidden pyramid is not pyramid. Flatten pyramid is not pyramid. Because what make pyramid is its shape, not because the order of operation it got

@Thaina
Copy link

Thaina commented Oct 4, 2018

@popcatalin81 And I think you misunderstand the most important point. That we don't deprecate or stop using the using block

I would still using the using block where I want a variable to stay only in small scope and should be to cleanup immediately. But using var is useful anywhere that we need to use that variable in the whole function. It not that we need to choose one. It just an option we have to make code more neatly

In fact I think it would be common to have using var inside using block such this

using(var something = LoadSomeThing())
{
    // Do something with something

    if(needAnotherThing)
    {
        using var anotherThing = LoadAnotherThing(); // can avoid pyramid
        // Do anything that need both something and anotherThing
    } // anotherThing dispose here

    // do some more thing relate to something but don't need anotherThing
}

// do some more thing not relate to something or anotherThing

Like this

@theunrepentantgeek
Copy link

It seems to me that this discussion is starting to repeat the same points over and over again.

I've seen other discussions in this repo where one of the parties has assumed that "disagreement" equals "not understanding", resulting in a tremendous amount of loud repetition.

I fear this issue might be heading in the same direction. I fervently hope it's not, and I would like to derail that if possible.

@popcatalin81 I'm just a random developer, participating here just because I find the process of language design endlessly fascinating. Please be assured that I have understood and appreciated the points you're making - and if I do, I'm pretty sure the LDM folks who make the decisions do as well.

@int19h
Copy link

int19h commented Oct 29, 2018

I hope that whatever syntax and semantics this proposal evolves into, will take into account the possibility of future evolution covering more than just local variables - and in particular, implicitly disposed fields / implicit implementation of IDispose (in the vein of C++/CLI destructors).

Note, I'm not saying that it should be a part of this proposal. Only that if such a direction is later taken, whatever is done here would serve as a natural basis - so it's best to pick an accommodating syntax today, so as to not have regrets over it in a few years.

With that in mind, and in the spirit of minor bikeshedding, how about owned as a keyword indicating that the variable should be automatically disposed once out of scope? While using is the historical choice of keyword for this in C#, and it's not unreasonable to try to reuse it, one could also argue that it's already unduly overloaded, and in any case makes more sense as an explicit block (with explicit block syntax, it reads as "using this, do that, [and then get rid of it]" - which it wouldn't as a modifier on a variable). On the other hand, resource ownership is really what this is all about - and with the growing popularity of Rust, it's more common to see the term used explicitly more often. So, as a keyword, it concisely and clearly captures the intent, more so than "using" or even "scoped" (all variables are scoped, after all!).

Here's the code snippet from the scoped proposal, restyled in this manner:

public static void CopyFile(string from, string into) 
{
    owned var fromFile = File.Open(from, FileMode.Open, FileAccess.Read);
    owned var toFile = File.Open(into, FileMode.Create, FileAccess.Write);
    // ... Perform actual file copy

    // Both FileStream objects are disposed at the end of the enclosing scope, 
    // in this case, the method declaration.
}

(And then perhaps var could be made implicit if no type is specified? There doesn't seem to be any particular reason to force it, and owned file reads better than owned var file.)

Such syntax would also extend naturally to ownership of objects referenced by another object via its fields, if some future proposal decides to go there, e.g.:

owner class Image {
    private owned FileStream stream;
    ...
}

@kkm000
Copy link

kkm000 commented Dec 5, 2018

FWIW, we have had this feature in F# for years, since v3, I believe, happy to have it, and see no troubles from it at all!

The syntax exactly follows that of the binding, only with a different keyword for scoped disposal (let to use ≈ var to using). I do not see absolutely any downside in introducing the 'using' [ var '=' ] expression ';' syntax; such a thing is nearly impossible not to grok to anyone who understands how var and the using(...) work, in my opinion.

scoped sounds about as useful as the keyword auto in C¹. You do know that C has the auto keyword, right? (Hint: auto int n; is same as int n;).

I am not going to quote examples to keep flame low, but I cannot help remarking that I've read many objections here that sound no better than patronizing. Please. C# is not intended as language to teach kindergartners how to program. A language that has no features that can potentially be misused is either not Turing-complete, or Haskell.

Cannot put it into words better than @CyrusNajmabadi did:

But I'll the one called to fix weird bugs because some dev has used a feature without understanding the semantics.

That's an issue with all language features :)
Don't understand 'async'? Then you're going to have weird bugs. Don't understand lambdas, or generics, or 'ref', or operators, or structs, or inheritance, or stacks, or memory, or etc. etc. etc.? Then you're going to have weird bugs. [...]
Heck, if you don't understand 'using' today, you're going to have issues.

Amen to that. Once you've learnt that await captures the synchronization context, unless you add a .ConfigureAwait(false) (false. FALSE, for gremlins sake!!!) to every single await you write, lest you run into supremely entertaining deadlocks on random contexts that you did not even know to exist, you've learnt everything you need to know. Which is do not assume anything whatsoever about any new feature, RTFM thrice, and then use the feature responsibly.

And "some devs" misuse the assignment operator too², but I still want it in the language, if you do not mind :-)


¹ confusingly, not to be confused with the auto in C++.
² I can think of List<MyStructType> a; ...; a[5].Answer = 42;, for example.

@int19h
Copy link

int19h commented Dec 5, 2018

using X = Y is already valid syntax in C# that means something else entirely (it introduces a namespace or a type alias).

@Joe4evr
Copy link
Contributor

Joe4evr commented Dec 8, 2018

using X = Y is already valid syntax in C# that means something else entirely (it introduces a namespace or a type alias).

But it's not legal to use inside of a method scope. In fact, the compiler doesn't even consider it being a namespace/type alias when used in a method scope, so there's no ambiguity here.

@DaZombieKiller
Copy link
Contributor

using X = Y is already valid syntax in C# that means something else entirely (it introduces a namespace or a type alias).

But it's not legal to use inside of a method scope. In fact, the compiler doesn't even consider it being a namespace/type alias when used in a method scope, so there's no ambiguity here.

I'm curious as to how that would interact with the scripting form of C#, where this doesn't necessarily apply.

@wanton7
Copy link

wanton7 commented Mar 19, 2019

This is great feature, but is there anything similar planned for namespaces?

Most if not all .cs files will have this wrapping namespace in them.

namespace MyNameSpace
{
    public class MyClass
    {
    }
}

It seems very redundant because most of the files will have single namespace just wrapping everything. It would be great to able to do this this instead

namespace MyNameSpace;

public class MyClass
{
}

@Joe4evr
Copy link
Contributor

Joe4evr commented Mar 19, 2019

@wanton7 #137.

@JesperTreetop
Copy link
Contributor

The documentation seems to imply that this (multi-declaration implicitly typed variables) is possible:

using var f2 = new FileStream("..."), f3 = new FileStream("...");

But it doesn't look to be possible with SharpLab. Is it supposed to be possible, and wouldn't it then clash with disallowing multi-declaration var generally?

I'd file this as a bug on the documentation but the proposal says the same thing.

@YairHalberstadt
Copy link
Contributor

@JesperTreetop
You can never use var with multiple declarations. You always have to specify the type explicitly.

@jcouv jcouv changed the title Champion "Implicitly scoped using statement" Champion "Implicitly scoped using statement" (16.3, Core 3) Jul 18, 2019
@munael
Copy link

munael commented Sep 9, 2019

Should #114 just mention this issue instead of both being put on the project board?

@333fred 333fred added the Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification label Oct 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification Proposal champion Proposal
Projects
None yet
Development

No branches or pull requests