LDM July 9th, 2018 ------------------- _QOTD: "Yeah, it's easy if you do it in a shi**y way"_ ## Agenda 1. `using var` feature 1. Overview 2. Tuple deconstruction grammar form 3. `using expr;` grammar form 4. Flow control safety 2. Pattern-based Dispose in the `using` statement 3. Relax Multiline interpolated string syntax (`$@`) # `using var` Feature **Motivation** Proposal: https://github.com/dotnet/csharplang/pull/1703 It's a common problem that multiple `using` statements can require successive nesting, causing what is mostly linear code to have the "down and to the right" problem, where increasing indentation makes the code less readable, not more. One way people try to solve this is using the ```C# { using (expr1) using (expr2) using (expr3) { ... } } ``` syntax, but that has two problems. First, many style guidelines prohibit "braceless" usings, but make an exception for this specific case. Second, if there is any intervening code required between the `using` expressions, this syntax form is not allowed. **Objections** Objections to this feature fall mainly in two categories. Either there is worry about determinism and ordering, or that this feature isn't sufficiently general to encompass the scenarios we would consider making the feature "worth it." The determinism concern is that refactoring from the `using (...) {...}` form could unintentionally lengthen the liveness scope to the entire method, instead of just to the closing brace of the using. The ordering concern is that nesting provides very clear ordering semantics, and the "stacked using" form also has a clear ordering, since there cannot be any code in between each `using`. This isn't necessarily true for using-variables. It's possible that both of these concerns could be mitigated by better refactoring and analysis tools. The generality concern is mainly around the `using (expr) { ... }` statement form, which doesn't have an equivalent using-variable form in the current design. **Conclusion** It's worth it. The concerns are valid, but don't seem bad enough to block the feature. ## Tuple deconstruction grammar form The first question was about the proposed grammar. The current design is a new type of statement (`local-using-declaration`). There are two potential holes in the grammar: no space for tuple deconstructions and no `using expr;` form. For deconstruction, we came up with a number of potential forms: ```C# (using var x, using var y) = M(); // Form 0 using (x, y) = M(); // Form 1 using (var x, var y) = M(); // Form 2 using var (x, y) = M(); // Form 3 using var t = M(); // Form 4 ``` Of these, only (4) would be legal in the current proposal. Of the remaining forms, form (0) seemed the clearest. There was consensus that this implied the declaration of two new variables, each of which was independently disposed, in the style of ```C# using var x = M1(), y = M2(); ``` It was not immediately clear whether the tuple itself was disposed in form (0). This was a common complaint with the rest of the forms as well: it is unclear what the semantics of each statement is. Is the tuple itself being disposed? Is disposal distributed over the elements? Both? Some tuple deconstructions also happen in "reverse" order of the tuple elements' lexical ordering. If dispose is distributed, what order are the elements disposed in? This also raised the question of nested declarations in the initializer, e.g. ```C# using var x = M1(out var y) ``` Is `x` the only `using` variable? Or is `y` one as well? **Conclusion** Let's continue with the proposal as-is. Form (4) works and should work. There may be compelling scenarios to open up the syntax to tuple deconstructions, but we don't have a convincing argument yet. We also don't have a clear rule for prohibition. For nested declarations, they are not declared as `using` variables. ## `using expr` grammar form These concerns dovetailed into discussion of the `using expr;` form, because some of these grammar forms may compose. For example, since `var (x, y)` is an expression in C#, the following could be a potentially legal statement with no modification: ```C# using var (x, y) = M(); ``` In this case `var (x, y) = M()` would be the `expr` in `using expr;`. This form seems desirable to round out the feature, but it isn't clear how it fits into the language. The previous decision seems to imply we don't want `using` deconstructions, but it isn't clear what rule we would use to prohibit them, in a principled sense. The feature also has some integration concerns. `using (expr);` is already a legal construct in the C# language with different semantics, although the compiler gives a warning about it today. There is some concern that `using expr;` and `using (expr);` are too close grammatically and that the syntax effectively rules out parenthesized expressions. Finally, there were questions about grammatical ambiguity with possible future language features. If C# were to allow statements on the top level, a `using System;` line could either be a using-directive if `System` is a namespace, or a using-statement if `System` is a type. The same problem could occur if we were to allow using-directives at the statement level. This doesn't seem very bad since we already have similar ambiguities with `Color Color` rules and resolve them properly during semantic analysis. These ambiguities are also probably present for using-directive aliases. There were a couple proposals to try to deal with some of these problems: 1. Any expression that declares variables is disallowed as a `using expr;` 2. Hold off on `using expr;` for now. 3. Allow `_` as a discard for `using var _ = expr;` - Or `using _ = expr;` **Conclusion** This is a blocking issue that we must decide on for C# 8.0. Either we should disallow this form entirely or find some principle to use to reject the constructions we find confusing. However, we think this problem is solvable and shouldn't block continued work on the feature. ## Flow control safety The last design issue was safety in the presence of `goto` and similar flow control features (e.g., local functions). The existing spec notes that backward flow control is not a problem, but what about forward flow control? For example, ```C# { goto target; using var x = new FileStream(...); target: var y = x; return; } ``` In the previous example, this is an error, because `x` is not definitely assigned. In fact, all uses in this category, where flow is manipulated to skip over the variable definition before a read, are safe because the variable will not be definitely assigned. In addition, because `using` variables are read-only, it also cannot be assigned later. One case which the spec does not currently handle is ```C# { goto target; using var x = new FileStream(...); target: return; } ``` Here `x` is never read, so there would be no definite assignment errors. However, there is an implicit read of the variable at the end of the variable lifetime, which could be a read of an unassigned variable. **Conclusion** A new line to the spec should be added saying that, if the end of a `using` variable's lifetime is reachable, that variable must be definitely assigned at that point. *Open question* * [ ] This needs more precise language. The spec does not have reachability at "points". What do we mean when we say the end of a block is "reachable"? # Pattern-based `using` statement We like the feature. Main question: what type of pattern do we look for? As a general guideline, we don't want to have another special case pattern. However, it seems like we have multiple styles already. - `GetAwaiter` doesn't allow `params` or optional parameters - LINQ does Do we want `using` to be like `await` or like LINQ? Also, do we require `void` return type? Most of the patterns today have strict requirements on return type, but they also usually consume the return type. `using` does not. **Conclusion** Keep the spec as is: `Dispose` must be parameter-less in instance-form, `void`-returning, and accessible. This allows for extension methods, but not optional parameters or `params`. # Multiline interpolated string syntax It's hard to remember which is the correct syntax: `$@""` or `@$""`. The proposal is to allow either. **Conclusion** No objections.