csharplang/meetings/2016/LDM-2016-11-30.md
2017-01-31 10:38:26 -08:00

127 lines
5.1 KiB
Markdown

C# Language Design Notes for Nov 30, 2016
=========================================
Agenda
------
- Scope of while condition expression variables
- Mixed deconstruction
- Unused expression variables
- Declarations in embedded statements
- Not-null pattern
Scope of while condition expression variables
=============================================
We are compelled by the argument in #15529 about the scope of expression variables occurring in `while` conditions.
``` c#
while (src.TryGetNext(out int x))
{
// Same or different `x` each time around?
}
// x in scope here?
```
More broadly we seem to have the following options for scopes and lifetimes of such declarations:
1. There is a single variable `x` for the whole `while` statement, which is initialized repeatedly, each time around. It is in scope outside the `while` statement.
2. There is a single variable `x` for the whole `while` statement, which is initialized repeatedly, each time around. It is only in scope inside the `while` statement.
3. There is a fresh variable `x` for each iteration of the `while` statement, initialized in the condition. It is only in scope inside the `while` statement.
There is a clear argument for the lifetime of the variable being a single iteration. We know from `foreach` that this leads to better capture in lambdas, but perhaps more importantly it avoids the odd behavior of the same variable getting initialized multiple times. (Pretty much the only way to otherwise achieve that in C# is through insidious use of `goto`).
This puts us squarely in option 3 above, where it is meaningless to put "the" variable in scope outside of a while loop. Indeed, from the outside there is no notion of "the" variable: there will be multiple `x`es over the execution of the loop.
Consequences in for loops
-------------------------
In light of a changed `while` loop we also need to examine what that means to the `for` loop, which, while not defined as such in the spec, can be informally understood as "desugaring" into a `while` loop.
``` c#
for (<decl>; <cond>; <incr>) <body>
==>
{
<decl>
while(<cond>)
{
<body>
cont:
{ <incr> }
}
}
```
So with respect to scopes and lifetimes, `<cond>` should behave the same as the condition in a while loop.
Similarly, `<incr>` should be a fresh variable each time around. Furthermore it should occur in its own little nested scope, since variables introduced in it won't be definitely assigned until the end of each iteration.
Conclusion
----------
We want to change to the narrow scopes and short lifetime for expression variables introduced in the condition of while and for loops, and in the increment of for loops.
This means that the `if` statement becomes more of a special case, with expression variables in its condition having broad scope. That is probably a good place to land. The main scenarios for this behavior are driven by the if statement to begin with, and it is also the one kind of statement where the lifetime and definite assignment situation for such variables makes it reasonable for them to persist outside of the statement.
Mixed deconstruction
====================
The reinterpretation of deconstruction in terms of declaration expressions would let us generalize so that:
- Would allow mixing existing and newly declared variables in a deconstruction
- Would allow newly declared variables in deconstruction nested in expressions
- No error when occuring as an embedded statement
Conclusion
----------
From a language design point of view we are confident in this generalization of the deconstruction feature. It is doubtful whether the change can make it into C# 7.0 at this point. Even though it is a small code change in and of itself, it introduces testing work and general churn.
Warn about unused expression variables?
=======================================
Should we warn when an expression variable goes unused? Typically such variables would be dummy variables, and with discards `_` you no longer need them.
On the other hand, we could leave it to the IDE to suggest discards etc, rather than give a warning from the language.
Conclusion
----------
Let's not add the warning. Keep the warning in place where it already is in existing C#.
Declarations in embedded statements
===================================
C# currently has a grammatically enforced restriction against declaring "useless" variables as "embedded statements":
``` c#
if (x > 3) var y = x; // Error: declaration statement not allowed as an embedded statement
```
Of course expression variables now give you new ways of similarly declaring variables that are immediately out of scope and hence "useless". Should we give errors for those new situations also?
Conclusion
----------
Let's not add errors for deconstruction situations. In principle we probably want to remove even the existing limitation, but it's work we won't push for in C# 7.0.
Pattern to test not-null?
=========================
It's been suggested to have a pattern for testing non-nullness (just as there is a `null` pattern for checking nullness).
Conclusion
----------
No time in C# 7.0 but a good idea.