First draft of enhanced using spec#31396
First draft of enhanced using spec#31396chsienki wants to merge 3 commits intodotnet:features/enhanced-usingfrom
Conversation
|
@dotnet/roslyn-compiler for review please |
|
enhanced foreach will be spec'd separately? Because I don't see that in feature status page either. |
|
@alrz I think "enhanced foreach" should be covered by this document too. We've been bundling enhanced using and enhanced foreach as one feature for tracking purpose. |
|
I'd suggest at least mention it in the status page so people know that's a thing. I myself wasn't sure until I saw the test plan. |
|
|
||
| __See__: the [corresponding proposal](https://github.com/dotnet/csharplang/blob/d2ce4cc3e17708e7e1d062bf40da0901a744fa3b/proposals/using.md) in CSharpLang. | ||
|
|
||
| _Pattern based dispose_ aims to make participation in the disposable pattern easier by relaxing the restrictions on what types can be used in a ```using(...){ }``` construct. |
There was a problem hiding this comment.
| _Pattern based dispose_ aims to make participation in the disposable pattern easier by relaxing the restrictions on what types can be used in a ```using(...){ }``` construct. | |
| _Pattern based dispose_ aims to make participation in the disposable pattern easier by relaxing the restrictions on what types can be used in a ```using(...){ }``` statement. |
|
|
||
| _Using declarations_ aim to make consuming a disposable type simpler by allowing ```using``` to be added to a variable declaration. | ||
|
|
||
|
|
|
|
||
| ## Pattern based dispose | ||
|
|
||
| Previously a type must derive from ```IDiposable``` / ```IAsyncDisposable``` and implement the ```void Dispose()``` / ```Task DisposeAsync()``` methods. With pattern-based dispose, a type can be considered 'disposable' if it meets certain structural requirements. Specifically: |
There was a problem hiding this comment.
You're missing something at the end of the first sentence. The sentence starts out with "Previously ..." but doesn't have a conclusion on what could be done previously.
|
|
||
| For ```using``` statements: | ||
|
|
||
| "A reachable, void returning method called Dispose, that can be called with zero parameters" |
There was a problem hiding this comment.
Believe you mean "arguments" instead of "parameters" here. I
There was a problem hiding this comment.
Probably should even be "explicit arguments" (here and below) to be more precise.
|
|
||
| For ```await using``` statements: | ||
|
|
||
| "A reachable, Task-like returning method called DisposeAsync, that can be called with zero parameters" |
| } | ||
| finally | ||
| { | ||
| if(x != null) x.Dispose(); // disposal |
There was a problem hiding this comment.
Now that we have is null consider using this code to represent the last line.
if (!(x is null)) x.Dispose();|
|
||
| This has the same effect as wrapping the declaration in a standard ```using(...){ }``` syntax, with the lifetime of the wrapped declaration being the same as that of the enclosing block. | ||
|
|
||
| _TODO_ No newline at end of file |
| @@ -0,0 +1,89 @@ | |||
| # Enhanced Using | |||
|
|
|||
| Enhanced using consists to two related features that aim to make the ```IDisposable``` coding pattern easier to participate in for implementers, and easier to consume for end users. | |||
There was a problem hiding this comment.
end users [](start = 171, length = 9)
nit: end-users
|
|
||
| __See__: the [corresponding proposal](https://github.com/dotnet/csharplang/blob/d2ce4cc3e17708e7e1d062bf40da0901a744fa3b/proposals/using.md) in CSharpLang. | ||
|
|
||
| _Pattern based dispose_ aims to make participation in the disposable pattern easier by relaxing the restrictions on what types can be used in a ```using(...){ }``` construct. |
There was a problem hiding this comment.
Pattern based [](start = 1, length = 13)
nit: Pattern-based (here and likely elsewhere)
|
|
||
| ## Pattern based dispose | ||
|
|
||
| Previously a type must derive from ```IDiposable``` / ```IAsyncDisposable``` and implement the ```void Dispose()``` / ```Task DisposeAsync()``` methods. With pattern-based dispose, a type can be considered 'disposable' if it meets certain structural requirements. Specifically: |
There was a problem hiding this comment.
Previously a type must derive [](start = 0, length = 29)
nit: something is off with the tense.
How about "A type was previously required to derive from ..."?
|
|
||
| Where reachable means legal to call from the site of the ```[await] using(...)``` under normal accessibility rules. | ||
|
|
||
| The ```Dispose``` / ```DisposeAsync``` methods are discovered using [Generalized Pattern Lookup](pattern-methods.md). In general if you could write ```c.Dispose()``` at the site of the ```using``` syntax and have it be a valid call under normal language rules, then the type is considered to be disposable. This includes implementation of ```Dispose``` via extension method, or methods with default or ```params``` parameters. |
There was a problem hiding this comment.
c.Dispose() [](start = 151, length = 11)
Should this be c?.Dispose() following this Monday's LDM?
|
|
||
| The design philopshy of the using statement is to only perform an action when there is a resource to be disposed. As such, null values are allowed, but no actions are performed. ```using(null){ }``` is valid syntax and the using is elided completely. ```using(IDisposable x = null){ }``` is also valid; the type is first checked for null before calling Dispose: when the using expression produces a null value there is no ```NullReferenceException``` thrown, and no Dispose method is called. This is extended as-is to pattern-based ```Dispose``` methods. | ||
|
|
||
| For extension method ```Dispose``` implmentations this means they will explictly *not* be invoked when the receiver is null, even though an equivilent call in code of ```x.Dispose()``` would result in the call being made with a null ```this``` parameter. This was a language decision to maintain the behavior that ```using``` perfoms no action when the resource being used is null valued. |
There was a problem hiding this comment.
equivilent [](start = 140, length = 10)
typo: equivalent
|
|
||
| The design philopshy of the using statement is to only perform an action when there is a resource to be disposed. As such, null values are allowed, but no actions are performed. ```using(null){ }``` is valid syntax and the using is elided completely. ```using(IDisposable x = null){ }``` is also valid; the type is first checked for null before calling Dispose: when the using expression produces a null value there is no ```NullReferenceException``` thrown, and no Dispose method is called. This is extended as-is to pattern-based ```Dispose``` methods. | ||
|
|
||
| For extension method ```Dispose``` implmentations this means they will explictly *not* be invoked when the receiver is null, even though an equivilent call in code of ```x.Dispose()``` would result in the call being made with a null ```this``` parameter. This was a language decision to maintain the behavior that ```using``` perfoms no action when the resource being used is null valued. |
There was a problem hiding this comment.
implmentations [](start = 35, length = 14)
typo: implementations
| @@ -0,0 +1,89 @@ | |||
| # Enhanced Using | |||
There was a problem hiding this comment.
The doc should be updated to reflect the recent restriction to ref struct types.
|
With the release of preview2, it would be nice to finish publish this document. |
|
Doc should call out restrictions on using-declaration statements:
|
|
It'd be good to revive and complete this PR for reference. Thanks |
|
Rev'd this as #34697 I've re-written most of this from scratch, but incorporated the feedback here for any of the bits that survived. Created a new branch + PR as this branch was very out of date. Closing. |
Initial draft for enhanced using speclet:
Notes: