14 comments

[ 2.6 ms ] story [ 39.7 ms ] thread
It makes you long for a dependently typed language where you really and truly can switch on decidable relations like "compare".

For example, I have some Agda code (totally unreadable to anyone who didn't write it, i.e. anyone who isn't me) where I switch on whether a+1 is less than, equal to, or greater than x+1, as part of the inductive step in an implementation of the division algorithm, rendering a number into a quotient and a remainder on division by another number. The type system guarantees that I haven't missed any cases. (https://github.com/Smaug123/agdaproofs/blob/9e22ba78f5446ce7...)

Switching on a comparison result has nothing to do with dependent typing. You can do this in Rust, where dependent typing has barely left the planning stages, last I checked.
I think I still prefer chaining "else if"s but I do appreciate seeing this new perspective on something I thought I knew like the pockets of my pants.
No, please don't do this. It's "clever" in all the wrong ways. It's not idiomatic use of switch, it's more code and line noise than simple if/else (all the switch(true), cases, and breaks are just syntactic salt), and it's not nearly as intuitive what happens if your conditions don't happen to be disjoint (in languages with a C-style switch you can control this to an extent with breaks vs. fallthrough but needless to say it's extremely fragile and confusing).

Even in languages with proper pattern matching it makes no sense to do something like the following instead of if/else:

  match x {
    x if x < 20 => foo(x),
    x if x >= 20 => bar(x),
    ...
  }
Avoiding complex if/else chains is a good idea, but replacing them with the same thing, only spelled differently , is not the way to do it.
While I agree switch on true might be an 'abuse' of the switch statement, I'm not sure about the last example.

In Elixir, I find myself using:

  if x do
    <blah>
  else
    <bleh>
  end
only in situations where I'm almost certain I won't end up having more cases, and in practice I tend to limit myself even to conditionals that are short, where I can do:

  if x, do: y, else: z
But in many, many situations I go for:

  case x do
    <condition 1> -> <stuff>
    <condition 2> -> <other stuff>
  end
because it looks cleaner, and because I often end up adding another condition.

Furthermore, there's also 'cond', which looks similar. using 'case' and 'cond' often just seems clearer to me over having a quite different syntax in the one situation where there's only two options ('if').

(not having to 'break' makes a big difference though)

What is the way to do it?

I like having functions with expressive names to encapsulate/hide complexity, and to comment what I'm doing. If it is not obvious why "20" is such a big deal in your code, then that's where I would trip up.

I don't mind having a few ifs if they look like this:

  if (isHoliday()) { }
  else if (isWeekend()) { }
Sure. But complex if/else logic, like I said, is often a code smell that indicates that the behavior might be better off abstracted out to a polymorphic entity of whatever sort is idiomatic in your language. There are a lot of "If statement considered harmful" style articles on the web, but I can't seem to find the specific one I had in mind :/
Yes, as a positive, I see that switch(true) will cosmetically align the tests of 'possible value 1' and 'possible value 2'.

But the negative is that you've added the requirement to always remember to include "break;" after each block. The code is prettier but also more fragile. This type of vigilant programmer discipline required to keep the code error-free (especially across multiple programmers) is not easy. Missing "break" statements causing unintended fallthrough are common bugs discussed in many "traps & pitfalls" books/blogs.

The "else if" while not as vertically aligned, includes the invisible "break;" for free.

(Side note that some languages like C#'s and Rust's switch statement don't have fallthrough behavior -- but this article uses PHP which does.)

If you really wanted to align your clauses, you also could do:

     if (false){
     } else if ($var=='possible value 1') {
       echo $var;
     } else if ($var=='possible value 2') {
       error_log($var);
     } else {
       // do nothing
     } 
Now we just to find somewhere where it would be a good idead...
Everything about this is very (2008)

1. Skeuomorphic torn-paper edge at the bottom

2. Loud background image on the body

3. Text is unreadably small on mobile

4. php

I’ve used this trick before. Thankfully in Go you would never need to do this, because in Go a switch statement with no predicate behaves this way by default.
For expression statements I usually chain .. ? .. : .., breaking lines before :
Ah, a lovely throwback to the bad old days of PHP and PHP programmers.

This is an ugly port of Lisl's "cond".