General Category > Ideas

Switch proposal

(1/3) > >>

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