Problems with mixed argument matching and case

I found an odd Elixir behavior. I’m not sure if I’m missing something really obvious or if this is a bug. It’s not something you actually want to do but I am wondering why Elixir does this.

The following script performs a simple conversion of a single letter or empty string into either a text or a :quit response. The first uses a case in a single function, the second uses a mix of one function argument matched for the :quit response and another function with a case for all of the other input.

The first works as expected but the second returns only the default case branch (“Unknown command”) for all input except the :quit response.

While you really do not want to use a mix of argument matching and case for a function, I am wondering why this second case behaves in this unexpected manner. (Forgive the indention. The code block on this forum is not working properly)

defmodule Test do
    def doCommand1(command) do
        case command do
            "a" -> {:ok, "A is for apple"}
            "b" -> {:ok, "B is for banana"}
            "c" -> {:ok, "C is for cherry"}
            "q" -> :quit
            ""  -> {:ok, "Try again"}
            _   -> {:ok, "Unknown command"}
        end
    end

    def doCommand2("q"), do: :quit
    def doCommand2(command) do
        case command do
            "a" -> {:ok, "A is for apple"}
            "b" -> {:ok, "B is for banana"}
            "c" -> {:ok, "C is for cherry"}
            ""  -> {:ok, "Try again"}
            _   -> {:ok, "Unknown command"}
        end
    end
end

IO.inspect Test.doCommand1("a")
IO.inspect Test.doCommand1("b")
IO.inspect Test.doCommand1("c")
IO.inspect Test.doCommand1("x")
IO.inspect Test.doCommand1("")
IO.inspect Test.doCommand1("q")
IO.puts ""
IO.inspect Test.doCommand2("a")
IO.inspect Test.doCommand2("b")
IO.inspect Test.doCommand2("c")
IO.inspect Test.doCommand2("x")
IO.inspect Test.doCommand2("")
IO.inspect Test.doCommand2("q")

Execution results in the following output.

{:ok, "A is for apple"}
{:ok, "B is for banana"}
{:ok, "C is for cherry"}
{:ok, "Unknown command"}
{:ok, "Try again"}
:quit
 
{:ok, "Unknown command"}
{:ok, "Unknown command"}
{:ok, "Unknown command"}
{:ok, "Unknown command"}
{:ok, "Unknown command"}
:quit

I have just copied-pasted your code into a new file, and under Elixir 1.3.4 I get the following output:

{:ok, "A is for apple"}
{:ok, "B is for banana"}
{:ok, "C is for cherry"}
{:ok, "Unknown command"}
{:ok, "Try again"}
:quit

{:ok, "A is for apple"}
{:ok, "B is for banana"}
{:ok, "C is for cherry"}
{:ok, "Unknown command"}
{:ok, "Try again"}
:quit
1 Like

Interesting. My Elixir version is:

Erlang/OTP 19 [erts-8.0] [64-bit] [smp:12:12] [async-threads:10]

Elixir 1.3.4
Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)

Can’t really help any more - the only thing I did change was indent the code correctly…