# Is there a "select case" equivalent in Julia?

**URL:** <https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516>\
**Category:** General Usage\
**Tags:** fortran, control-flow\
**Created:** [August 16, 2021, 9:50pm UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516 "2021-08-16T21:50:10Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![CRquantum](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/crquantum/32/27824_2.png) [@CRquantum](https://discourse.julialang.org/u/CRquantum)\
**Post date:** [August 16, 2021, 9:50pm UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/1 "2021-08-16T21:50:10Z")

</div>

Here is a small Fortran subroutine, with select case,

```
subroutine steps(it)
integer(kind=i8) :: it
select case (imode)
	case (11)
		call step11(it)
	case (12)
		call step12(it)
	case default
		write (6,'(''Illegal imode value: '')') imode
		stop
end select    
return
end subroutine steps

```

I wonder, is there a select case equivalents in Julia?

Of course I can use if statement, but a select case could be nicer especially if there are a lot of cases.

Thanks in advance!

---

<div class="post-metadata">

**Author:** ![gbaraldi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gbaraldi/32/22101_2.png) [@gbaraldi](https://discourse.julialang.org/u/gbaraldi)\
**Post date:** [August 16, 2021, 10:07pm UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/2 "2021-08-16T22:07:00Z")

</div>

Unfortunately not, you can do a sequence of if else statements and there might be some packages that do pattern matching, although if I would guess the if else statements are faster.

---

<div class="post-metadata">

**Author:** ![greg\_plowman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/greg_plowman/32/8100_2.png) [@greg\_plowman](https://discourse.julialang.org/u/greg_plowman)\
**Post date:** [August 16, 2021, 11:00pm UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/3 "2021-08-16T23:00:33Z")

</div>

The discussion here might be relevant: [A switch type function](https://discourse.julialang.org/t/a-switch-type-function/13491)

---

<div class="post-metadata">

**Author:** ![CRquantum](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/crquantum/32/27824_2.png) [@CRquantum](https://discourse.julialang.org/u/CRquantum)\
**Post date:** [August 17, 2021, 11:56pm UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/4 "2021-08-17T23:56:53Z")

</div>

If I have many cases, just say 20 cases,  
it is a little difficult for me believe that if statements can be faster, because if I have to select the last case, I need to do like 19 if judges. Besides, the if else if else statements may be cumbersome somehow.  
But if there is a select case thing in Julia, it can quickly jump to the last case without doing if statements.

Am I wrong or missing something?

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [August 18, 2021, 12:15am UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/5 "2021-08-18T00:15:32Z")

</div>

Seems pretty quick:

```julia
julia> ex = :("last");

julia> for i in 50:-1:1
         ex = :(x == $i ? $("value " * string(i)) : $ex)
       end

julia> @eval f(x) = $ex
f (generic function with 1 method)

julia> @btime f(r[]) setup=(r=Ref(2))
  1.166 ns (0 allocations: 0 bytes)
"value 2"

julia> @btime f(r[]) setup=(r=Ref(51))
  1.166 ns (0 allocations: 0 bytes)
"last"

julia> ex
:(if x == 1
      "value 1"
  else
      if x == 2
          "value 2"
      else
          if x == 3
              "value 3"
          else
              if x == 4
                  "value 4"
...

```

---

<div class="post-metadata">

**Author:** ![Juan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juan/32/7657_2.png) [@Juan](https://discourse.julialang.org/u/Juan)\
**Post date:** [August 18, 2021, 12:37am UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/6 "2021-08-18T00:37:01Z")

</div>

It’s quick but much more confusing.

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [August 18, 2021, 12:53am UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/7 "2021-08-18T00:53:49Z")

</div>

@mcabbott isn’t saying that’s how you should write them, he’s just generating a very large set of if statements (by metaprogramming) which will perform exactly the same as handwritten ones, and then showing those are fast (and therefore handwritten ones are as well).

---

<div class="post-metadata">

**Author:** ![viraltux](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/viraltux/32/15236_2.png) [@viraltux](https://discourse.julialang.org/u/viraltux)\
**Post date:** [August 18, 2021, 3:07am UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/9 "2021-08-18T03:07:40Z")

</div>

> [@CRquantum](#):
>
> I need to do like 19 if judges. Besides, the if else if else statements may be cumbersome somehow

Perhaps using a Dict would be more convenient where the case is the key and the call is the value?

---

<div class="post-metadata">

**Author:** ![ToucheSir](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/touchesir/32/14411_2.png) [@ToucheSir](https://discourse.julialang.org/u/ToucheSir)\
**Post date:** [August 18, 2021, 4:34am UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/10 "2021-08-18T04:34:13Z")

</div>

I believe the kind of pattern you show up top will be compiled to a switch ~~and then jump table~~ (via Julia and LLVM respectively), much like I assume a Fortran compiler could.

Edit: it doesn’t generate a jump table, but I wasn’t able to coax gfortran to create one either on Godbolt. If someone figures out how to, please let me know 🙂

Adapting that example:

```julia
step11(it) = print("step11", it)
step12(it) = print("step12", it)

function steps(it)
  if it === 11
    step11(it)
  elseif it === 12
    step12(it)
  else
    throw("illegal value $it")
  end
  return
end

```

`@code_llvm steps(1)` clearly shows a jump table being constructed:

```llvm
define void @julia_steps_214(i64 signext %0) #0 {
top:
  %1 = alloca [2 x {}*], align 8
  %gcframe3 = alloca [3 x {}*], align 16
  %gcframe3.sub = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe3, i64 0, i64 0
  %.sub = getelementptr inbounds [2 x {}*], [2 x {}*]* %1, i64 0, i64 0
  %2 = bitcast [3 x {}*]* %gcframe3 to i8*
  call void @llvm.memset.p0i8.i32(i8* nonnull align 16 dereferenceable(24) %2, i8 0, i32 24, i1 false)
  %thread_ptr = call i8* asm "movq %fs:0, $0", "=r"() #8
  %ppgcstack_i8 = getelementptr i8, i8* %thread_ptr, i64 -8
  %ppgcstack = bitcast i8* %ppgcstack_i8 to {} ****
  %pgcstack = load {} ***, {}**** %ppgcstack, align 8
; @ REPL[3]:2 within `steps`
  %3 = bitcast [3 x {}*]* %gcframe3 to i64*
  store i64 4, i64* %3, align 16
  %4 = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe3, i64 0, i64 1
  %5 = bitcast {} **%4 to {}***
  %6 = load {} **, {}*** %pgcstack, align 8
  store {} **%6, {}*** %5, align 8
  %7 = bitcast {} ***%pgcstack to {}***
  store {} **%gcframe3.sub, {}*** %7, align 8
  switch i64 %0, label %L11 [
    i64 11, label %L3
    i64 12, label %L8
  ]

L3: ; preds = %top
; @ REPL[3]:3 within `steps`
; ┌ @ REPL[1]:1 within `step11`
   call void @j_print_216({}* inttoptr (i64 140108222856496 to {}*), i64 signext 11) #0
; └
  br label %L14

L8: ; preds = %top
; @ REPL[3]:5 within `steps`
; ┌ @ REPL[2]:1 within `step12`
   call void @j_print_217({}* inttoptr (i64 140108217624080 to {}*), i64 signext 12) #0
; └
  br label %L14

L11: ; preds = %top
; @ REPL[3]:7 within `steps`
  %8 = call nonnull {}* @jl_box_int64(i64 signext %0)
  %9 = getelementptr inbounds [3 x {}*], [3 x {}*]* %gcframe3, i64 0, i64 2
  store {}* %8, {}** %9, align 16
  store {}* inttoptr (i64 140108212808048 to {}*), {}** %.sub, align 8
  %10 = getelementptr inbounds [2 x {}*], [2 x {}*]* %1, i64 0, i64 1
  store {}* %8, {}** %10, align 8
  %11 = call nonnull {}* @jl_apply_generic({}* inttoptr (i64 140108035749248 to {}*), {}** nonnull %.sub, i32 2)
  call void @jl_throw({}* %11)
  unreachable

L14: ; preds = %L8, %L3
  %12 = load {}*, {}** %4, align 8
  %13 = bitcast {} ***%pgcstack to {}**
  store {}* %12, {}** %13, align 8
; @ REPL[3]:9 within `steps`
  ret void
}

```

See [Computed goto (or labels as values) in Julia?](https://discourse.julialang.org/t/computed-goto-or-labels-as-values-in-julia/5013) for more.

For a terser way of switching on values, have a look into [https://github.com/thautwarm/MLStyle.jl:](https://github.com/thautwarm/MLStyle.jl:)

```julia
using MLStyle
...
function steps_match(it)
  @match it begin
    11 => step11(it)
    12 => step12(it)
    _ => throw("illegal value $it")
  end
  return
end

```

I’ve verified that this also generates a switch at the LLVM level.

---

<div class="post-metadata">

**Author:** ![CRquantum](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/crquantum/32/27824_2.png) [@CRquantum](https://discourse.julialang.org/u/CRquantum)\
**Post date:** [August 18, 2021, 4:43am UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/11 "2021-08-18T04:43:15Z")

</div>

Thanks!  
This looks like a solid answer, although I am not very clear what does the script you displayed mean. But I believe Julia should be smart enough to do jumping instead of doing a lot of unnecessary if judgements.

Just curious, why use ‘===’ in things like

```
if it === 11

```

why not just use “==” ?

---

<div class="post-metadata">

**Author:** ![casparvitch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/casparvitch/32/14100_2.png) [@casparvitch](https://discourse.julialang.org/u/casparvitch)\
**Post date:** [August 18, 2021, 4:48am UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/12 "2021-08-18T04:48:24Z")

</div>

Perhaps to ensure it’s an integer. `12 === 12.0` evaluates as false. (If you want info on the operator use `?===` in the REPL).

---

<div class="post-metadata">

**Author:** ![CRquantum](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/crquantum/32/27824_2.png) [@CRquantum](https://discourse.julialang.org/u/CRquantum)\
**Post date:** [August 18, 2021, 4:52am UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/13 "2021-08-18T04:52:07Z")

</div>

Thank you! You are absolutely right.

---

<div class="post-metadata">

**Author:** ![Keno](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/keno/32/285_2.png) [@Keno](https://discourse.julialang.org/u/Keno)\
**Post date:** [August 18, 2021, 5:02am UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/14 "2021-08-18T05:02:14Z")

</div>

When writing patterns matching things, I sometimes use a macro like this:

```julia
function mkcond(cond)
    if isexpr(cond, :call) && cond.args[1] == :(|)
        return Expr(:(||),
            mkcond(cond.args[2]),
            mkcond(cond.args[3]))
    else
        return :(cond == $(esc(cond)))
    end
end

macro case(cond, cases)
    block = ret = Expr(:block, Expr(:(=), :cond, esc(cond)))
    done = false
    first = true
    for case in cases.args
        isa(case, LineNumberNode) && continue
        isa(case, Expr) || error("Expected Expr, got $(typeof(case))a")
        done && error("Extra statements after catchall")
        if isexpr(case, :call) && case.args[1] == :(=>)
            casecond = case.args[2]
            casestmt = case.args[3]
            if casecond == :(_)
                push!(block.args, esc(casestmt))
                done = true
                continue
            end
            stmt = Expr(first ? :if : :elseif,
                mkcond(casecond),
                esc(casestmt))
            push!(block.args, stmt)
            block = stmt
            first = false
        else
            error("Unknown stmt kind $(case)")
        end
    end
    ret
end

```

Usage:

```julia
julia> function steps(it)
           @case imode begin
               11 => step11(it)
               12 => step12(it)
               (13 | 14) => whatever()
               _ => error("Illegal imode value")
           end
       end

```

You can make the match syntax do whatever you want. Probably a good candidate for somebody to make a macro that defines a more extensive set of match syntaxes for various common situations.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [August 18, 2021, 5:12am UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/15 "2021-08-18T05:12:23Z")

</div>

There are also packages providing tuple-backed dictionaries. They are close to switch or if performance, but are more composable/reusable.  
See Dictionaries.jl and OrderedCollections.jl.

---

<div class="post-metadata">

**Author:** ![Per](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/per/32/10387_2.png) [@Per](https://discourse.julialang.org/u/Per)\
**Post date:** [August 18, 2021, 9:23am UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/16 "2021-08-18T09:23:15Z")

</div>

What I frequently do is something like:

```julia
function steps(imode, it)
   step(Val(imode), it)
end

function step(::Val{11}, it)
    # The subroutine step11 from Fortran
end

function step(::Val{12}, it)
    # The subroutine step12 from Fortran
end

function step(::Val{M}, it) where {M}
    # Without this function, we'd get a MethodError instead 
    # (which might be just as useful).
    error("Illegal imode value: ", M)
end

```

It might be slightly slower (about a microsecond) compared to an `if` statement, but I find the syntax much nicer. It also makes it possible to support additional cases from external code.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [August 18, 2021, 10:22am UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/17 "2021-08-18T10:22:37Z")

</div>

@ToucheSir, regarding the LLVM switch business, do you think it is faster to use the `MLStyle` package instead of the simple & clean chained ternaries solution by @mbauman in [this post?](https://discourse.julialang.org/t/a-switch-type-function/13491/19) (_which was also linked above_)

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [August 18, 2021, 12:30pm UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/18 "2021-08-18T12:30:03Z")

</div>

My Fortran is a bit rusty so apologies if I missed something, but I would do something like

```julia
function steps(it, imode)
    function _select(m)
        m == 11 && return step11(it)
        m == 12 && return step12(it)
        error("Illegal imode value")
    end
    _select(imode)
end

```

ie move the `case` logic to a function and just use `return`.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [August 18, 2021, 12:37pm UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/19 "2021-08-18T12:37:24Z")

</div>

or if you don’t want to type `return` multiple times and your brain is indentation agnostic:

```julia
function steps(it, imode)
    function _select(m)
        return if m == 11
            step11(it)
        elseif m == 12
            step12(it)
        end
             error("Illegal imode value")
    end
    _select(imode)
end

```

---

<div class="post-metadata">

**Author:** ![greatpet](https://avatars.discourse-cdn.com/v4/letter/g/e495f1/32.png) [@greatpet](https://discourse.julialang.org/u/greatpet)\
**Post date:** [August 18, 2021, 2:38pm UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/20 "2021-08-18T14:38:12Z")

</div>

With `@code_llvm`, I see that `if..elseif..else` chains are compiled into LLVM switch statements, at least for the simple cases I checked. Will the latter eventually be compiled into a jump table?

I’ve read elsewhere that if the cases are sparsely distributed, e.g. 1, 100, 400, 800, 1000, then a C compiler will compile the switch statement into something like a binary search rather than a jump table.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [August 18, 2021, 2:39pm UTC](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516/21 "2021-08-18T14:39:19Z")

</div>

Probably missing something, but why not doing the chained ternaries that seem to be damn fast?

```julia
function steps(imode, it)
    imode == 11 ? step11(it) :
    imode == 12 ? step12(it) :
    error("Illegal imode value")
end

```

[Next page](https://discourse.julialang.org/t/is-there-a-select-case-equivalent-in-julia/66516.md?page=2)
