9
votes

On the iex console, I found the following error that I'm unsure what I've done wrong...

case %{} do
  x when x == %{} -> true
  _x -> false
end

Results in the following error:

** (ErlangError) erlang error: :guard_expr

Also, I wanted to explain how I found this. I attempted to make my own || macro by looking at elixir's implementation and changing it to treat [], {}, and %{} the same as false and nil. https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/kernel.ex#L2313

Here's that implementation (it has the same problem):

defmodule Or do
  defmacro left || right do
    quote do
      case unquote(left) do
        x when x in [false, nil] or x == [] or x == {} or x == %{} ->
          unquote(right)
        x ->
          x
      end
    end
  end
end

Taking away the or x == %{} makes things work.

1
Strange. Using a variable in place of the literal compiles, i.e: y = %{}; case y, do: (x when x == y -> true; _x -> false) - Christian
Yes and its only maps that cause a problem, [] or something else doesn't crash it. - mgwidmann
Strangely, when this same guard is used in a function definition it does not crash... - mgwidmann
It appears this is an Erlang bug. I could reproduce this in the pure Erlang shell. I can't find any reference about this behaviour. In any case, until this gets resolved, you should consider some workaround, such as the one proposed by @Christian. - sasajuric
Maybe on Erlang bugs mailing list (erlang.org/mailman/listinfo/erlang-bugs). This is the Erlang code that reproduces it: case #{} of X when X == #{} -> X end. I should mention I tried with Erlang 17.0. Perhaps it's fixed on 17.4, but I don't have it installed to verify. - sasajuric

1 Answers

1
votes

This appears to be an Erlang bug. Here is the erlang code to reproduce the issue:

case #{} of X when X == #{} -> X end.

Thanks to everyone for confirming! See comments for more details.