General Category > Ideas
Switch proposal
lerno:
Putting it here instead as a comment in a longer discussion
Here is the propsal:
--- Code: ---switch (a) {
case 1 | // Using : instead of | is syntax sugar for case 1: goto next;
case 2 |
case 3:
foo(); // With : we get a break;
case 4 |
case 5:
bar();
goto next; // If we want to execute a statement then pass to next.
case 6:
baz();
}
// The above in C:
switch (a) {
case 1:
case 2:
case 3:
foo();
break;
case 4:
case 5:
bar();
case 6:
baz();
break;
}
--- End code ---
Another possibility is |: or :|
--- Code: ---switch (foo) {
case 1|:
case 2|:
case 3:
do_something();
--- End code ---
Using | means a that some care must be taken if there is an expression of type:
case 1|2: (This is is compiled to case 3: or course, but I think it's reasonable to require ( ) on any constant expression that isn't a literal.
So case 1+2: would not be allowed, but case (1+2): is ok.
Alternatives to goto next would be:
--- Code: --- case 4:
foo();
fallthrough;
case 5:
...
case 4:
foo();
goto case 5;
case 5:
...
case 4:
foo();
goto case;
case 5:
...
case 4:
foo();
continue case;
case 5:
...
case 4:
foo();
next;
case 5:
...
case 4:
foo();
next case;
case 5:
...
case 4:
foo();
nextcase;
case 5:
...
--- End code ---
An even more lightweight syntax uses | for fallthrough, leading to this uniform syntax look:
--- Code: --- case 4:
foo();
| case 5:
...
--- End code ---
--- Code: ---switch (a) {
case 1:
| case 2:
| case 3:
foo(); // implicit break here
case 4 :
| case 5:
bar(); // Fallthrough here because the next starts with |
| case 6:
baz();
}
--- End code ---
lerno:
Real life example of this kind of switch:
--- Code: ---switch (D->getKind()) {
case DECL_FUNC:
expr->setConstant();
case DECL_VAR:
VarDecl* VD = cast<VarDecl>(D);
QualType T = VD->getType();
if (T.isConstQualified()) {
Expr* Init = VD->getInitValue();
if (Init) {
// Copy CTC status of Init Expr
expr->setCTC(Init->getCTC());
}
expr->setConstant();
return;
}
case DECL_ENUMVALUE:
expr->setCTC(CTC_FULL);
expr->setConstant();
return;
case DECL_ALIASTYPE |
case DECL_STRUCTTYPE |
case DECL_ENUMTYPE |
case DECL_FUNCTIONTYPE |
expr->setConstant();
case DECL_ARRAYVALUE |
case DECL_IMPORT |
case DECL_LABEL:
}
--- End code ---
lerno:
And the uniform | syntax instead:
Real life example of this kind of switch:
--- Code: ---switch (D->getKind()) {
case DECL_FUNC:
expr->setConstant();
case DECL_VAR:
VarDecl* VD = cast<VarDecl>(D);
QualType T = VD->getType();
if (T.isConstQualified()) {
Expr* Init = VD->getInitValue();
if (Init) {
// Copy CTC status of Init Expr
expr->setCTC(Init->getCTC());
}
expr->setConstant();
return;
}
case DECL_ENUMVALUE:
expr->setCTC(CTC_FULL);
expr->setConstant();
return;
case DECL_ALIASTYPE:
| case DECL_STRUCTTYPE:
| case DECL_ENUMTYPE:
| case DECL_FUNCTIONTYPE:
expr->setConstant();
case DECL_ARRAYVALUE:
| case DECL_IMPORT:
| case DECL_LABEL:
// do nothing.
}
--- End code ---
lerno:
Also to discuss, should we automatically open a scope or not. If we automatically open a scope in cases, we prevent this nice code:
--- Code: ---switch (state) {
case READ_WITH_LOCK:;
LOCK *lock = acquire_lock();
defer lock.release();
case READ_WITHOUT_LOCK:
read_from_resource();
break;
case ...
}
--- End code ---
This since the implicit scope would trigger the defer when passing into the READ_WITHOUT_LOCK (I assume current syntax, so this is fallthrough automatically)
Of course, we could make | / fallthrough mean that scope is shared. That would make this execute correctly (new syntax):
--- Code: ---switch (state) {
case READ_WITH_LOCK:;
LOCK *lock = acquire_lock();
defer lock.release();
| case READ_WITHOUT_LOCK:
read_from_resource();
case ...
}
--- End code ---
lerno:
Yet one more syntax:
--- Code: ---switch (a) {
case 1, // Comma to delimit multiple case. Can only be followed by another case
case 2,
case 3: // : means we have an explicit break.
foo();
case 4,
case 5:
bar();
goto next; // Explicit fallthrough (could also be goto case, goto case 6 etc)
case 6:
baz();
}
--- End code ---
Navigation
[0] Message Index
[#] Next page
Go to full version