Guards! Guards!

hauleth.dev · 2026-06-28 · by Long Nguyen ·generic
Blog about BEAM, Rust, fantasy & stuff Guards! Guards! Small gotcha about boolean operators in Elixir.

Guards! Guards!

Guards! Guards!

2026.06.27 :: 2 min :: #beam

Let's start with simple quiz.

---

Given module defined as:

defmodule Foo do
  def a(x) when is_integer(x) or is_map_key(x, :foo), do: true
  def a(x), do: false

def b(x) when is_map_key(x, :foo) or is_integer(x), do: true def b(x), do: false end

Try to answer these questions.

Q: What will be result of `Foo.a(%{foo: 21})`?

`true`

`false`

WRONG

RIGHT

This one is straightforward.

We check guard, it has one condition `is_integer(x) or is_map_key(x, :foo)`. First one returns `false`, second returns `true`, Boolean's alternative results in `true` and first case is matched.

Q: What will be result of `Foo.a(37)`?

`true`

`false`

WRONG

RIGHT

This one is straightforward as well.

We check guard, it has one condition `is_integer(x) or is_map_key(x, :foo)`. First one returns `true`, second one isn't fired at all, because `or` operator is short circuiting.

Q: What will be result of `Foo.b(%{foo: 21})`?

`true`

`false`

WRONG

RIGHT

Again, similar to the previous questions.

We check guard, it has one condition `is_map_key(x, :foo) or is_integer(x)`. First one returns `true` and the rest is short circuited.

Q: What will be result of `Foo.b(37)`?

`true`

`false`

WRONG

RIGHT

Ouch, something changed…

Again, we check guard, one condition `is_map_key(x, :foo) or is_integer(x)`. We hit first clause `is_map_key(x, :foo)` and this doesn't return `false`, instead it fail. Failure in one of guard functions isn't converted to `false` but instead makes whole guard expression fail. This mean that `is_integer(x)` part will never be called.

---

This behaviour is often surprising for a lot of Elixir developers, as it seemingly breaks commutative property of boolean operators. However, to be honest, these never were commutative because of short circuiting.

It seems that Elixir at the time of writing (Elixir 1.20.1, OTP 29) do not warn about this issue.

∎

Author of this post is currently open for hire (CV).

You can contact me at lukasz@niemier.pl

---

You can provide feedback via mailing list \~hauleth/blog@lists.sr.ht (archive).

Webmentions:

  • <https://lemmy.bestiver.se/post/1193297>
  • <https://bsky.app/profile/did:plc:6psaz6n5fuurrfet67zs4ljf/post/3mpbudsxwi22h>
hauleth.dev · 20 links

Comments (0)

No comments yet