Julia 2.0: superSwitch or SuperCase ... or generalized if-then-else statement

Julia doesn’t have a switch/case statement. I recall reading the past that @StefanKarpinski tried to interest the other developers back in the day, but couldn’t get them excited about it. That makes some sense – early on, you have a list of 20,000 things you wan to do, and the language already has if-then-else, so switch/case would be a low priority.

However, in the drive to Julia 2.0, let me make the case [sic] for the a switch-case statement.

Except - I don’t want a switch-case statement as usually implemented.

Let’s look at the typical switch-case syntax:

switch (age) {
  case 1:  printf("You're one.");            break;
  case 2:  printf("You're two.");            break;
  case 3:  printf("You're three.");
  case 4:  printf("You're three or four.");  break;
  default: printf("You're not 1,2,3 or 4!");
}

The problem I have with it, and the reason I rarely use it (in languages that have it), is that it’s too limiting. All the cases are constants you’re comparing against the variable.

According to Wikipedia, switch-case statements come in two semantic forms: structured and unstructured. The example above is “unstructured,” where cases are treated as labels within a single block, and the switch functions as a generalized goto. The second form, “structured”, is a generalized if-then-else, with any number of branches, not just two. The Wikipedia also notes two forms, one which requires a “break” statement after each evaluated expression, and those that assume a “break” and you have to put in “continue” if you want it to fall through.

It’s the structured form I’ve always wanted in a language. Usually, I want to operate on ranges of the variable, not single values.

What I would like is switch-case compares to is an expression (expr1, which evaluates to true/false), then if it evaluates to true, executes another expression (expr2, which could be anything). This is really just a generalized if-then-else, with fallthrough in some cases. I could swear one language I used let me do this, but perhaps it’s just mis-memory: I usually wanted to do this, but went away disappointed.

Generic syntax is

Switch(var;
      expr1 : expr2
	  expr1 : expr2 
	  etc.
	  )

Where expr1 has to evaluate to true/false, and expr2 can be anything. If you want fallthrough, you put continue after expr2.

We’ve all probably encountered a math function that is defined like this:

f(x) = \begin{cases} -1 & \text{if } x < 0 \\ \infty & \text{if } x = 0 \\ 1 & \text{if } x > 0 \end{cases}

This would be a natural for my superSwitch/SuperCase:

function delta(x)
    Switch(x;

        x < 0 : y = 0

        x == 0 : y = Inf

        x > 0  : y = 0 

    )

    return y

end 

Of course, after the “:” could be many more statements. This example also illustrates an “assumed break statement” after Expr2; if one wants it to fall-through, one puts in “continue”:

function controlmachine(Θ)

    switch(Θ;
    
        Θ ≥ 120 && θ < 330         : θ = θ-90
                                     continue 

        θ ≥ 0 && Θ < 30 || Θ ≥ 330 : direction = "East"
                                     speed = 5
                                     force = 2
                                     # assumed break here 

        Θ > 30 && θ < 60           : direction = "NorthEast"
                                     speed = 6
                                     force = 3
                                     # assumed break here 
                                     
        θ ≥ 60 && Θ < 120           : direction = "North"
                                      speed = 5
                                      force = 1.3
    )                                # assumed break here

    return (direction, speed, force)

end 

Of course, what is the variable doing in the Switch statement at all?

switch(Θ;

It doesn’t need to be there, as the variable is in each condition (expr1). In fact, you could have multiple variables in the conditions. Again, it’s a generalized if-then-else with fallthrough in some cases.

So don’t call it Switch or Case. Call it something else. BlockIf or Examine:

    BlockIf(
    
        Θ ≥ 120 && θ < 330         : θ = θ-90
                                     continue 
    Examine(
    
        Θ ≥ 120 && θ < 330         : θ = θ-90
                                     continue 

Now, clearly, this is a convenience syntax for the user. It could, of course, be implemented as if-then-else statements.

However, it would be very convenient. I run into this pattern a lot – having to execute different statements based on a range of a variable. The advantage to the user is the ease of construction and the clarity of the presentation.

Note I have ignored the scoping rules. I would assume the scoping rules would be the same as they are for if-then-else (indeed, I would expect the compiler to deconstruct the syntax into a series of if-then-else constructs).

Now, I’m not a computer scientist. The developers may have very good reason not to do something like this. However, I would love it if they did. It would be a distinctive feature of Julia, and I would use it a lot.

Thanks for taking time to consider it.

I think the advanced version of this feature is MLStyle.jl’s pattern matching.

@match data begin
    pattern1 => result1
    pattern2 => result2
    ...
    patternn => resultn
end

This is under active development, so I wouldn’t rush to add it to the language.

One thing that is somewhat unfortunate with this design is that the C style switch statement can generate an O(1) lookup table, which can be really nice in some cases.

That is something that can compiler should be able to do these days. Also it’s basically impossible/undesired to have a equivalent syntax as C switch in julia (way too restricted).