Skip to content

Ranges do not equal when it seems they should in a guard #12076

@ollien

Description

@ollien

Elixir and Erlang/OTP versions

Erlang/OTP 24 [erts-12.3.2.1] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit]

Elixir 1.13.4 (compiled with Erlang/OTP 24)

Operating system

Fedora 36

Current behavior

I wanted to write a function that would, given a range and a value, n, check if the range spans exactly n..n. My first attempt looked something like this, but does not have the expected behavior (note the first return value is false)

defmodule Range do
  def equal?(n, range) when range == n..n, do: true
  def equal?(n, range), do: false
end

IO.puts(Range.equal?(1, 1..1)) # false
IO.puts(Range.equal?(1, 1..5)) # false

While this function can be written by using pattern matching on the range argument (replacing the first equal? declaration with def equal?(n, n..n), do: true), I was surprised this didn't work.

Some on StackOverflow have speculated this is due to the step evaluating to nil in a guard. Indeed, it does work if when range == n..n is replaced with when range == n..n//1

Expected behavior

I would have expected when range == n..n to correctly guard the call for when the range was exactly n..n, especially given this works

iex(1)> range = 1..1
1..1
iex(2)> n = 1
1
iex(3)> range == 1..1
true
iex(4)> match?({n, n..n}, {1, 1..1})
true

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions