0

What is the best practices to handle multiple condition cases if they are not bound to one variable?

For Example we could use else if statement:

if (a && b > 10) {
    ...
} else if (a && b < 5) {
    ...
} else if (!a && c === 'test') {
    ....
} else if (!a && c === 'test2') {
    ...
} else {
    ...
}

That is just example, so don't try to simplify it by regrouping logic. Notice that we can't use simple switch here. We can't use map with options either. As an alternative we can use switch(true) to make it more readable:

switch(true) {
    case (a && b > 10):
        ...
        break;
    case (a && b < 5):
        ...
        break;
    case (!a && c === 'test'):
        ...
        break;
    case (!a && c === 'test2'):
        ...
        break;
    default:
        ...
}

It is absolutely legal and recommended by many authors. But from the other hand many developers don't like it as true statement is not a variable but constant.

I've read a few posts about switch(true) usage. Like following: javascript switch(true)

What would be the best solutions for such multiple conditions without one single variable?

Solution: I end up with simplified version of Erik Philips answer. Thank you Erik!

let descriptionByType: {description: string, check: check: () => Boolean}[] = [
    { description: 'result 1', check: () => a && b > 10 },
    { description: 'result 2', check: () => a && b < 5 },
    { description: 'result 3', check: () => !a && c === 'test' },
    { description: 'result 4', check: () => !a && c === 'test2' },
    { description: 'default result', check: () => true },
];
return descriptionByType.find(x => x.check()).description;

It is quite clear and flexible.

Alex Vovchuk
  • 2,828
  • 4
  • 19
  • 40
  • 2
    I would say, it is a matter of taste. I have never seen the `switch (true)` syntax before, and actually think, it is a "freakish" usage of the switch statement, as it was most likely not intended to be used this way. My preference would be to stick with the `if-else if-else` blocks. Most development tools are also able to collapse if blocks nicely, so, if you need an overview, you can get it that way. `switch` block collapse support is probably much more sparse. – Christoph Herold Sep 03 '19 at 14:34
  • 2
    Yes, `switch(true)` is absolutely horrible, and requires you to deal with fallthrough. It is less readable than the `if`/`else` chain that you *meant*, and deceives the reader. – Bergi Sep 03 '19 at 14:34
  • Btw, you could do `if (a) { if (b > 10) { … } else if (b < 5) { … } } else { if (c == 'test) { … } else if (c == 'test2') { … } }` (you could `switch` on `c` if you see an advantage) – Bergi Sep 03 '19 at 14:38
  • Christoph Herold, we can wrap case body in curly braces and will be able to collapse. It is useful if case body is big. – Alex Vovchuk Sep 03 '19 at 14:38
  • same, switch(true) looks like sth went wrong first option is the best for me – Krzysztof Kaczyński Sep 03 '19 at 14:38
  • 1
    This seems like either an opinion question or an exact duplicate of the linked question. What should we do here? – jcalz Sep 03 '19 at 14:43
  • Possible duplicate of [switch (true) as alternative to else if](https://stackoverflow.com/questions/20596572/switch-true-as-alternative-to-else-if) – jcalz Sep 03 '19 at 14:48

2 Answers2

1

Too many if statements/switch logic can cause issues with testing and Cyclomatic Complexity.

The generally accepted solution to this is to store your logic in a list/dictionary along with the function that is associated with it (not a perfect example):

public class LogicalFunc
{
  Logic: () => boolean;
  Func: () => void;
}

const logicalFunctions: LogicalFunc[] = [
  new LogicalFunc {
    Logic: (a: number, b: number) => (a && b) > 10,
    Func: () => someOtherFunc(),
  }
];

function myFunction(a: number, b: number) {

  const logicalFunc = logicalFunctions.find(lf => lf.Logic(a,b));
  if (logicalFunc) {
    logicalFunc.Func();
  } else {
    // some default
  }
}

function someOtherFunc() {}

Now your logical tests are separate from the method which means you can test the list independently of the myFunction. You can also overwrite the list to test the only two possible outcomes of the myFunction, either an item was found or it wasn't found. The overwritten list for the positive would be:

  new LogicalFunc {
    Logic: (a: number, b: number) => true,
    Func: () => void(),
  }

and the negative would have an empty list.

Eliminating Cylclomatic Complexity by replacing switch/case with a method or a Dictionary<TKey, func<>> (c#)

Refactoring Switch Statements To Reduce Cyclomatic Complexity (c#)

Cyclomatic complexity refactoring tips for javascript developers

No ifs…alternatives to statement branching in JavaScript

sergeyski.com
  • 586
  • 6
  • 14
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • Yes, looks really impressive. Should be excellent solution especially for big number of cases. I have never seen such implementation before. Could you please provide some links to read? – Alex Vovchuk Sep 03 '19 at 17:46
  • Added links for alternatives/better descriptions. – Erik Philips Sep 03 '19 at 19:02
0

As I'm sure you know, there really isn't a right answer here. Whatever is more readable is the best option. I think you'll find other developers will be much happier reading an if, else chain rather than a boolean switch statement (there is a time and a place). Given your example I would try to break it into more general statements and then dig deeper from there. For example, rather than this:

if (a && b > 10) {
    ...
} else if (a && b < 5) {
    ...
} else if (!a && c === 'test') {
    ...
} else if (!a && c === 'test2') {
    ...
} else {
    ...
}

maybe, this:

if (a) {
    if (b > 10) {
        ...
    } else if (b < 5) {
        ...
    }
} else {
    if (c === 'test') {
        ...
    } else if (c === 'test2') {
        ...
    }
}

In your case this doesn't quite work since this solution doesn't accommodate the final else statement in the chain, but my point is that in most cases an easy to read if, else chain with complex logic has slim boolean statements and is as linear as possible. In my opinion there is no need to get a switch statement involved unless you really need it.

kylestrader94
  • 83
  • 1
  • 4