DEV Community

Cover image for Reverse switch?
Gabriel Rufino
Gabriel Rufino

Posted on

Reverse switch?

I recently saw something that caught my attention and I called it Reverse Switch. Probably there's a better name.

A conditional switch where the expression takes boolean constants (true or false) and the switch cases take expressions.

Some like this:

switch (true) {
  case isEven(x):
    console.log('x is even!')
    break
  case isPrime(x):
    console.log('x is prime!')
    break
  case x > 10:
    console.log('x is greater than 10')
    break
  default:
    console.log('x is not even, is not prime and is not greater than 10')
}
Enter fullscreen mode Exit fullscreen mode

My head exploded because I never thought about it.
I always did it as follows:

if (isEven(x)) {
  console.log('x is even!')
} else if (isPrime(x)) {
  console.log('x is prime!')
} else if (x > 10) {
  console.log('x is greater than 10')
} else {
  console.log('x is not even, is not prime and is not greater than 10')
}
Enter fullscreen mode Exit fullscreen mode

And here comes my question:

  1. Have you seen or done something like that?
  2. Do you think it is good practice?
  3. Which one is more readable?

Let's talk about it!

Top comments (12)

Collapse
 
tqbit profile image
tq-bit • Edited

I personally don't use (or like) switch, it makes code hard to read. And I believe there are cases in which if - else is the only viable option, but given the choice, I'd always favor single if() - clauses that return a value if the expression is met. It's like using switch, with the default statement at the bottom of the function bound to no other if-clause. When I get back to the code after a few weeks, I'm usually glad I did it this way.

Very simple pseudocode sample for simple http - server

try {
  const { clientId } = req.params;

  const found = await Client.findOne({ clientId });
  const hasAccess = await Auth.findOne({clientId});

  if (!found) {
    return res.status(404).send(itemNotFound);
  }

  if(!hasAccess) {
    return res.status(401).send(userNotAuthorized);
  }

  await Client.deleteOne({ clientId });
  res.status(200).send(deleted);
} catch (e) {
  res.status(500).send(internalError);
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
darthbob88 profile image
Raymond Price

The closest I've seen to that sort of wackiness is putting function pointers in an array and then indexing them, like so.

logTrue = () => console.log("It's true");
logFalse = () => console.log("It's false");
var foo = [logFalse, logTrue]
foo[+true]() //Chrome doesn't convert directly from true to 1, so have to do this to convert it.
/// "It's true"
Enter fullscreen mode Exit fullscreen mode

It's clever, but I would absolutely not allow it in production code.

Collapse
 
mellen profile image
Matt Ellen-Tsivintzeli • Edited

It is bad. Do not do it.

It is counter intuitive and, from my experience debugging other people's code, the source of bugs.

Collapse
 
codinghusi profile image
Gerrit Weiermann

Well the switch seems more readable than the if else ^^

Collapse
 
mellen profile image
Matt Ellen-Tsivintzeli

It is difficult to maintain, far more so than an if statement. This is primarily because it breaks convention, i.e. surprises are bad, and also because the structure is not suited to keeping track of which thing you want to be true.

If you are having this much trouble with if statements, then I would recommend looking at refactoring them into a clearer flow, not misusing switch syntax.

Thread Thread
 
mangoduck profile image
mangoduck • Edited

So much opinion. If something works, reliably, it's no misuse. Heck, use nothing but lambdas if you want, if it does the job how you want. (You could make a religion outta that...) If it feels contrived then maybe that's just not the place, but when you do find the place, it's beautiful, intuitive, and trivial to maintain.

You know exactly what's going to happen. Every expression will be evaluated in order until one matches, in this case, true, just like conditionals. Unlike conditionals though it doesn't have to be true, could be 3, another expression, function calls that return success or status, etc. Don't forget you have the option of not breaking as well. Lots of neat stuff is possible.

Collapse
 
xanderyzwich profile image
Corey McCarty

It seems really clever!

Clever code should not be used in production unless it is completely necessary, and then it should be commented/whitespaced in such a way to improve the readability. I'd never thought about this, and it does seem quite usable as long as you don't intend on using the code for more than 6 months or letting anyone else look at it.

Collapse
 
fjones profile image
FJones • Edited

A good rule of thumb I follow for switch(bool) vs if {} else if {} else {} and restructuring:

  • switch(bool) if only one of the conditions can be true for any input, and there is a clear default case. Good example here is implementing compare/spaceship.
  • if {} else if {} else {} if there is overlap between the conditions and order matters. FizzBuzz says hello.
  • restructure the whole thing if order matters but there is no overlap. This particular case almost always indicates a function that does too much.

This also goes with readability: distinct cases make sense for switch(bool) and actually eliminate having to think about order of operations, if applied consistently like this. Small aside: this of course only applies for immediate(-ish) returns, not for complex behaviour within.

Collapse
 
vonheikemen profile image
Heiker

Have you seen or done something like that?

I have done something like that. Only in one side project. I don't hate it, but I also don't love it.

Do you think it is good practice?

It isn't. I don't think is bad, but is so uncommon that I bet people will run the other way the moment they see it.

Which one is more readable?

The one you're more familiar with.

Collapse
 
ssimontis profile image
Scott Simontis

I think the switch statement is more elegant and readable, although I feel the most elegant solution is pattern matching, which you see in functional languages like OCaml or F#.

Collapse
 
jankapunkt profile image
Jan Küster

Switch is fine, use it without break but return and it's fairly readable

Collapse
 
codinghusi profile image
Gerrit Weiermann

Oh that's a pretty neat idea!
Rust has i in some way, but not exactly that 😊