DEV Community

loading...
Cover image for Reverse switch?

Reverse switch?

gabrielrufino profile image Gabriel Rufino ・1 min read

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!

Discussion (11)

pic
Editor guide
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
mellen profile image
Matt Ellen • 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

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.

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
feichinger 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
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
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 😊