We propose a form of expression that allows you to declare temporary variables before the final result of the expression. We replace the existing parenthesized expression with the following
_parenthesized-expression_:
(_sequence-statements_opt _expression_)
_sequence-statements_:
_sequence-statement_ _sequence-statements_
_sequence-statement_
_sequence-statement_:
_expression-statement_
_declaration-statement_
The scope of any variable declared in a _parenthesized-expression_ is the body of that _parenthesized-expression_.
The type of a _parenthesized-expression_ is the type of its final expression.
At run-time the statements are executed in sequence, and then the final expression is evaluated, which becomes the value of the whole sequence expression.
The definite assignment and reachability rules need to be specified, but they are trivial.
This is particularly useful in combination with the expression form of the pattern matching construct #5154.
/cc @TyOverby
love this :+1:
Why not
parenthesized-expression:
{sequence-statementsopt expression-statement}
sequence-statements:
sequence-statement sequence-statements
sequence-statement
sequence-statement:
expression-statement
declaration-statement
?
@orthoxerox it will be ambiguous in expression-bodied lambdas (discussed at length in #5402).
@orthoxerox Because that would break compatibility by making (1+1) a syntax error for two reasons - first, because 1+1 is not one of the expression forms allowed as an _expression-statement_, and second, because it lacks the semicolon that is part of an _expression-statement_.
Oh, wait, you're suggesting that we replace the parens in a parenthesized expression with curly braces? I think that would make lots of things ambiguous.
Why is it named sequence?
@paulomorgado Because it evaluates the expressions sequentially for side effects. Got a better name?
@gafter, this used to be referred as declaration expressions, right.
Aren't you afraid it might be confused with "as opposed to asynchronous expressions"?
And, no! I don't have a better name. Yet!
What is its result type? That of the last expression? I receive the impression from the name "sequence expression" that its result type is an array of each expression.
@paulomorgado No, this is not the same as declaration expressions. That was where you could declare a variable at its first use, something like M(int x = 12, x*x).
The type and value is the type and value of the last expression.
See?
@paulomorgado I'm not sure you understand. This would not be legal under this proposal:
M(int x = 12, x*x)
That's because a local declaration (with or without its semicolon, which is normally part of its syntax) is not an expression. If you wanted to do something like that with this proposal, you'd have to write
(int x = 12; M(x, x*x))
OK! Got it, @gafter!
My "See?" comment was regarding this:
@paulomorgado:
Aren't you afraid it might be confused with "as opposed to asynchronous expressions"?
and this:
@ufcpp
I receive the impression from the name "sequence expression" that its result type is an array of each expression.
But given your last example, sequence is starting to make sense to me.
@gafter Since you invited the bikeshedding, I think "chained expressions" would be a nice name. It doesn't have the connotation of sounding like a list or a generator, and the "chain" imagery helps show that expressions can depend on results produced by previous ones.
FYI, gcc calls a similar C extension "statement expression".
Seems it will introduce a little inconsistency with the for statement, which uses comma.
Ugly code:
``` C#
for (int i = 0, j = 1; (int k = i + j; M(k, k)); i++, j *= 2)
{
}
Though people won't mix them in practice.
It will also be possible to write silly program like this, which does not look like C#:
``` C#
public double Foo() => (
int a = GetSomething();
Log(a);
DoSomething(a);
);
Sub
The scope of any variable declared in a parenthesized-expression is the body of that parenthesized-expression.
This conflicts with current scoping of is var and out var
var x = (e is T t ? t : foo);
// t is in scope!
Probably this should be decided now if this feature is planned for a future release.
Issue moved to dotnet/csharplang #377 via ZenHub
Most helpful comment
This conflicts with current scoping of is var and out var
Probably this should be decided now if this feature is planned for a future release.