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.

5 Likes

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.

6 Likes

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.

5 Likes

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).

2 Likes