3

In an answer to this question, the most popular answer states this is the best way to do it:

switch(variable) {
    case 0:
        // operation A;
    case 1:
        // operation B;
        break;
}

But what if operation B MUST be performed before operation A? In that case, is this acceptable, or is there a better solution:

switch(variable) {
    case 0:
    case 1:
        // operation B;
        break;
    case 0:
        // operation A;
        break;
}
Tara
  • 389
  • 3
  • 14
  • So for `case 0` you want B, then A, and for `case 1` you want just B? In that case I'd consider using two `switch` blocks, depending on the number of other cases. –  Feb 23 '18 at 00:23
  • @BorisLobanov there will be no runtime errors, but it is certainly not perfectly fine, it is bad practice and would not have the desired behavior of the OP. – Matthew Ciaramitaro Feb 23 '18 at 00:38

3 Answers3

3

The break will force you out of the switch, in a case like that it would be better to double up the operation like so

switch(variable){
    case 0:
       //operation B
       //Operation A
       break;
    case 1:
       // Operation A
       break;
}

The best method to avoid too much double up of code would be to break operations A and B into separate functions meaning only 2 lines are needed for the switch i.e.

switch(variable){
    case 0:
       this.DoOperationB(variables)
       this.DoOperationA(variables)
       break;
    case 1:
       this.DoOperationA(variables)
       break;
}
Rando
  • 473
  • 2
  • 12
  • Out of all given answers, this is how I would personally do it as well: it's clear, avoids code duplication and functions are generally a nice thing to have. – Marco Feb 23 '18 at 00:35
  • This answer is better for more general cases where we have many more than two operations that we want to perform in specific orders. This is due to the order of the switch table needing to become more complex depending on the restraints. For this simple example my solution would be better, but Rando's solution is best practice. – Matthew Ciaramitaro Feb 23 '18 at 00:41
  • this is probably the best way to do it, I was just trying to avoid breaking up the code (the operation is not really large or complex enough to warrant it) – Tara Feb 23 '18 at 00:51
3

Solutions

To force both cases to perform process B we can list them in order with no break statements, and then use an if statement instead of the duplicate case statement you used to perform the operation not required of case 1.

switch(variable) {
    case 0:
    case 1:
        // operation B;
        if(variable === 0) //operation A ;
        break;
    
}

or alternatively nesting functions will be a good solution if process B would precede process A no matter the circumstance.

process_A = function(){
  process_B();
  console.log("running operation A");
  //operation A;
}
process_B = function(){
  console.log("running operation B");
  //operation B;
}
variable = 0;
switch(variable) {
    case 0:
        process_A();
        break;
    case 1:
        process_B();
        break;
        
}

Explanation of Switch Tables and Duplicate Cases

It doesn't make sense to include duplicate cases in a switch table. Only 1 case will be indexed by variable. If you require complex relationships between conditions you probably need to use ifelse blocks or something along the line of Rando's solution.

The following snippet demonstrates why you should never use duplicate cases in a switch table:

var variable = 0;
switch(variable) {
    case 0:
        console.log("case 0: No Op performed");
    case 1:
        // operation B;
        console.log("case 1: Op B performed");
        break;
    case 0:
        // operation A;
        console.log("case 0: Op A performed");
        break;
}

Notice how operation A never runs.

A switch table is similar to an array. Each case is an index of the table, which allows us to quickly handle conditions, rather than moving linearly down ifelse blocks. When we index a switch table we perform all commands from that index to the end of the table or until the first break

Community
  • 1
  • 1
Matthew Ciaramitaro
  • 1,184
  • 1
  • 13
  • 27
  • 1
    This would be the preferred answer. – Dencio Feb 23 '18 at 00:27
  • yeah, I was just trying to avoid duplicating code and calling functions, but I guess I'm going to have to do one or the other. Thanks! – Tara Feb 23 '18 at 00:47
  • @TaraStahler I see, so you want case 0 to run operation B and operation A, and case 1 to just run operation B? – Matthew Ciaramitaro Feb 23 '18 at 00:56
  • yeah, exactly. But the catch is, case B needs to be run first – Tara Feb 23 '18 at 00:58
  • @TaraStahler I've adjusted my solution to match this behavior, with one solution using no functions or duplicate code, and the other using functions but not duplicating code. – Matthew Ciaramitaro Feb 23 '18 at 01:10
  • 1
    ha, yeah...it's not elegant, but I fear there is no elegant solution for this particular case (the if statement's redundant) ^^ – Tara Feb 23 '18 at 02:13
  • Well the if statement isn't redundant because we combined case 0 and case 1 into a single case so it simply seperates between the two. But yes there are probably no elegant solutions without functional abstraction. – Matthew Ciaramitaro Feb 23 '18 at 02:19
0

Easy to test and see it doesn't work quite like you'd want:

function doStuff(x) {
  console.log(`with ${x}:`);
  switch (x) {
    case 0:
    case 1:
      console.log("operation B");
      break;
    case 0:
      console.log("operation A");
      break;
  }
}
doStuff(0);
doStuff(1);

The second case 0, while syntactically legal, will never be reached by code. In these cases it is usually best to combine the case labels as appropriate, and then use ifs (or even more switches) to dispatch to different operations.

Aurel Bílý
  • 7,068
  • 1
  • 21
  • 34