Comment #0 by andrej.mitrovich — 2013-09-19T10:40:13Z
Currently if you want to handle an unhandled case in a switch statement you can use a default statement. For example:
-----
import std.string;
auto get() { return "c"; }
void main()
{
auto res = get();
switch (res)
{
case "a": break;
case "b": break;
default: assert(0, format("Unhandled case: '%s'", res));
}
/// res still visible here, we don't want it to be.
}
-----
The problem here is that you're unnecessarily creating the 'res' variable which you will only use for the default statement. Additionally, such a variable shouldn't be visible outside the switch statement if it's only going to be used inside of the switch statement.
I propose we allow an auto statement in the switch statement:
-----
import std.string;
auto get() { return "c"; }
void main()
{
switch (auto res = get()) // new: allow auto statement
{
case "a": break;
case "b": break;
default: assert(0, format("Unhandled case: '%s'", res));
}
}
-----
This will also eliminate the need for code duplication in switch statements which use a common label statement, for example:
-----
import std.string;
import std.stdio;
auto get() { return "d"; }
void main()
{
switch (auto res = get())
{
case "a": goto common;
case "b": goto common;
case "c": goto common;
common:
writefln("Got result: %s", res);
break;
default: assert(0, format("Unhandled case: '%s'", res));
}
}
-----
Comment #1 by bearophile_hugs — 2013-09-19T13:16:07Z
(In reply to comment #0)
> Additionally, such a variable
> shouldn't be visible outside the switch statement if it's only going to be used
> inside of the switch statement.
That's easy solved:
auto get() { return "c"; }
void main() {
import std.string;
{
auto res = get;
switch (res) {
case "a": break;
case "b": break;
default: assert(0, format("Unhandled case: '%s'", res));
}
}
// res not visible here.
}
> This will also eliminate the need for code duplication in switch statements
> which use a common label statement, for example:
>
> -----
> import std.string;
> import std.stdio;
>
> auto get() { return "d"; }
>
> void main()
> {
> switch (auto res = get())
> {
> case "a": goto common;
> case "b": goto common;
> case "c": goto common;
>
> common:
> writefln("Got result: %s", res);
> break;
>
> default: assert(0, format("Unhandled case: '%s'", res));
> }
> }
Usually common bodies for case statements are not a big problem in D:
auto get() { return "d"; }
void main() {
import std.stdio, std.string;
{
auto res = get;
switch (res) {
case "a", "b", "c":
writefln("Got result: %s", res);
break;
default:
assert(0, format("Unhandled case: '%s'", res));
}
}
// res not visible here.
}
Comment #2 by andrej.mitrovich — 2013-09-19T13:22:09Z
(In reply to comment #1)
> That's easy solved.
That's really ugly. It also gets twice as ugly if you have to use a static if.
> Usually common bodies for case statements are not a big problem in D.
Sometimes you have to call specific code for each of these cases, but then follow them with a generic call. So you use a goto to a single label. At the point of the label you won't know what the switch value is unless you stored it somewhere, e.g. (pseudocode):
void main()
{
switch (auto x = get)
{
case "a": handleA(); goto common;
case "b": handleB(); goto common;
case "c": handleC(); goto common;
common: log_output(x); break;
default:
}
}
Comment #3 by monarchdodra — 2013-09-19T14:49:31Z
Well, not just auto, you just want to be able to make a declaration inside the switch expression. This would also apply to a while statement too.
In C++, this is legal:
//----
while (int i = 1)
{}
switch (int i = 1)
{}
//----
This is a very reduced use case, but I've seen cases where it is useful.
The D grammar does not allow it though. I don't see why not though.
Comment #4 by andrej.mitrovich — 2013-09-19T15:10:21Z
(In reply to comment #3)
> Well, not just auto, you just want to be able to make a declaration inside the
> switch expression.
Yeah, I'll rename the title.
Comment #5 by monarchdodra — 2013-09-20T00:53:31Z
(In reply to comment #3)
> Well, not just auto, you just want to be able to make a declaration inside the
> switch expression. This would also apply to a while statement too.
>
> In C++, this is legal:
>
> //----
> while (int i = 1)
> {}
>
> switch (int i = 1)
> {}
> //----
>
> This is a very reduced use case, but I've seen cases where it is useful.
>
> The D grammar does not allow it though. I don't see why not though.
To answer my own self:
> while (int i = 1)
> {}
This would probably be illegal in D anyways, since we aren't allowed assignments in if/for/while. Arguably, it's not an "assignment" but a "declaration", so it shouldn't be a problem either. Still, it's a thin line, and I have (albeit very rarely) also made that "typo", when copy pasting code.
> switch (int i = 1)
> {}
Switch is special, because it doesn't actually test the args, so I see better chances of this being made legal.
IMO, while the use cases arn't very important, not supporting this for switch would just be a gratuitous deviation from C++ (IMO). Then again, C doesn't support it either (afaik), so...
Comment #6 by andrej.mitrovich — 2014-01-29T00:29:57Z
*** Issue 11988 has been marked as a duplicate of this issue. ***
Comment #7 by andrej.mitrovich — 2014-02-17T08:40:59Z
http://forum.dlang.org/post/[email protected] :
-----
That bugzilla is a minor improvement that has precedent in the "if"
statement, so I'd accept "switch (auto var = expr)" if implemented.
-----
Tagging as preapproved.
Comment #8 by dlang-bugzilla — 2014-08-18T18:04:13Z
Created attachment 1435
allow vardecls in switch()
seems to work, but not heavily tested.
Comment #11 by ketmar — 2014-09-27T01:37:08Z
Created attachment 1436
simple testcase
no grammar fixes, sorry.
Comment #12 by dlang-bot — 2023-10-07T00:25:16Z
@Mai-Lapyst created dlang/dmd pull request #15656 "Fix issue 11070 - Allow declaration statement in a switch expression" fixing this issue:
- Fix issue 11070 - Allow declaration statement in a switch expression
https://github.com/dlang/dmd/pull/15656
Comment #13 by b2.temp — 2023-10-08T11:11:29Z
It was not the case in the 2013 but 10 years later adding this feature is a failure to recognize the more general pattern: the VarDecl as used in this proposal could be a primary expression and should not be tied to specific statements.
1. First this was possible as IfStatement condition.
2. Then it was added as WhileStatement condition
3. Now it will be added as SwitchStatement condition
4. In the future someone will realize that
- this is useful to deconstruct tuples
- this is useful in AndEnExpression and OrOrExpression
- this is useful in the CallExpression for the `out` parameters
etc. etc.
Making the new primary would fix that in one shot.
Comment #14 by dlang-bot — 2023-10-09T00:02:45Z
dlang/dmd pull request #15656 "Fix issue 11070 - Allow declaration statement in a switch expression" was merged into master:
- f123432a608274bd9d7f377abc86db10e66dc0dc by Mai-Lapyst:
Fix issue 11070 - Allow declaration statement in a switch expression
- d6ba4f7981961a8baa9c80cdd9ac681bfa7134f4 by Mai-Lapyst:
Update tests for issue 11070 to match test suite requirements
https://github.com/dlang/dmd/pull/15656