[Proposal] Shorthand for Declaration Expressions #7652
Replies: 3 comments
-
See: #377 The team has also expressed some interest in a form of syntax that would allow |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
For me, this example code highlights the problems around allowing either switch expression arms to contain a statement blocks, or having some form of declaration expression. The OP's code can be expressed as: static Card[]? Format(string format, string[] data, DateTime[] times, int[] ranks)
{
switch (format)
{
case "pairs":
return DoTimes(
data.Length / 2,
i => new Card(data[i * 2], data[i * 2 + 1], times, ranks, i));
case "properties":
var (before, after, rest) = (data[0], data[1], data[2..]);
return DoTimes(
rest.Length / 2,
i => new Card($"{before} {rest[i * 2]} {after}", rest[i * 2 + 1], times, ranks, i));
case "element":
var (i, name, symbol, number, mass, group, oxide) =
(0, data[0], data[1], data[2], data[3], data[4], data[5]);
return [
new Card($"What is the symbol of {name}?", symbol, times, ranks, i++),
new Card($"What is the atomic number of {name}?", number, times, ranks, i++),
// similar lines omitted
];
default: return null;
}
} There's no (mis)use of switch expressions as means of assigning variables in this version, which simplifies the code. But there are now a bunch of returns, a switch statement etc, so this seems an ideal candidate for say declaration expressions: static Card[]? Format(string format, string[] data, DateTime[] times, int[] ranks)
=> format switch {
"pairs" =>
DoTimes(
data.Length / 2,
i => new Card(data[i * 2], data[i * 2 + 1], times, ranks, i));
"properties" => (
var (before, after, rest) = (data[0], data[1], data[2..]);
DoTimes(
rest.Length / 2,
i => new Card($"{before} {rest[i * 2]} {after}", rest[i * 2 + 1], times, ranks, i));
),
"element" => (
var (i, name, symbol, number, mass, group, oxide) =
(0, data[0], data[1], data[2], data[3], data[4], data[5]);
[
new Card($"What is the symbol of {name}?", symbol, times, ranks, i++),
new Card($"What is the atomic number of {name}?", number, times, ranks, i++),
// similar lines omitted
]
),
_ => null;
}; Now those three And of course, if you really want to avoid a switch statement, the code can simplified via breaking pieces of separate functionality out into separate functions: static Card[]? Format(string format, string[] data, DateTime[] times, int[] ranks)
=> format switch {
"pairs" => HandlePairs(data, times, ranks),
"properties" => HandleProperties(data, times, ranks),
"element" => HandleElement(data, times, ranks),
_ => null
};
static Card[]? HandlePairs(string[] data, DateTime[] times, int[] ranks)
=> DoTimes(
data.Length / 2,
i => new(data[i * 2], data[i * 2 + 1], times, ranks, i));
static Card[]? HandleProperties(string[] data, DateTime[] times, int[] ranks)
{
var (before, after, rest) = (data[0], data[1], data[2..]);
return DoTimes(
rest.Length / 2,
i => new($"{before} {rest[i * 2]} {after}", rest[i * 2 + 1], times, ranks, i));
}
static Card[] HandleElement(string[] data, DateTime[] times, int[] ranks)
{
var (i, name, symbol, number, mass, group, oxide) =
(0, data[0], data[1], data[2], data[3], data[4], data[5]);
return [
new Card($"What is the symbol of {name}?", symbol, times, ranks, i++),
new($"What is the atomic number of {name}?", number, times, ranks, i++),
// similar lines omitted
];
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Declaration expressions were added to C# with the advent of version 8.0. They take the form of
<expression> switch { <type> <pattern> => <expression> }
, the value of which is equal to the body expression. A larger example (which is perhaps somewhat ill-advised):Proposal
The shorthand for these expressions would take the form
let <type> <pattern> = <expression> in <expression>
. This syntax uses existing C# keywords and its compilation and evaluation can match that of the above (though such an expression should allow binding a nullable value).The above expression reformulated using this shorthand:
Drawbacks
The use of
let
in this manner may be ambiguous with respect to its use in LINQ. The use ofin
, while syntactically distinct, differs from its previous use for iterating through collections. Further expansion of C#'s expressions may be distasteful to its community, and all shown above can be achieved in the form of statements.Alternatives
The format
let (<type> <pattern> = <expression>) <expression>
may be more familiar to C# programmers, though less so to those experienced with F# and OCaml. Potential ambiguity with the LINQ syntax remains.The type declaration could be removed, making the syntax more similar to LINQ (until the
in
is reached). This would work better if LINQ gained patterns, which has been proposed elsewhere.using
could be used instead oflet
, though it already has several associated meanings, a new keyword could be created, or the leading keyword could be dropped (though I expect that would render it more difficult to read).Beta Was this translation helpful? Give feedback.
All reactions