TIL
You can override existing infix operators in your modules by very simple means.
When ever I needed to implement and
/or
functions in my modules, I’ve defaulted to using and_/or_
function names, since a module with and/or
functions defined as below fails with a syntax error:
defmodule Operator do
def and(left, right) do
:ok
end
end
So I’ve been doing this:
defmodule Operator do
def and_(left, right) do
:ok
end
def or_(left, right) do
:ok
end
end
I always considered it to be due to and
being a keyword and not being able use the same name in my functions. This is however not the case. It just have to use the correct def
construct:
defmodule Operator do
# with pattern matching
def (%{key: value} = _left) and (%{key: value} = _right) do
:ok
end
def left and right do
:ok
end
end
However what happens when having another function which uses and
in guards?
defmodule Operator do
def left and right do
:ok
end
def other_function(value1, value2) when value1 == 1 and value2 == 2 do
:ok
end
end
$ mix compile
** (CompileError) : imported Kernel.and/2 conflicts with local function
(elixir 1.12.2) src/elixir_locals.erl:94: :elixir_locals."-ensure_no_import_conflict/3-lc$^0/1-0-"/2
(elixir 1.12.2) src/elixir_locals.erl:95: anonymous fn/3 in :elixir_locals.ensure_no_import_conflict/3
(stdlib 3.15.2) erl_eval.erl:685: :erl_eval.do_apply/6
Kernel functions are automatically imported, Kernel.and/2
is a built in macro that can be used in guard expressions. As long as were not using Kernel.and/2
in guards we can call it directly from the function to avoid the conflict i.e:
def some_func(value1, value2) do
Kernel.and(value1 == 1, value2 == 2)
end
And actually the same thing can be done to resolve the conflict for the guards as well:
defmodule Operator do
alias Kernel, as: K
def left and right do
:ok
end
def other_function(value1, value2) when K.and(value1 == 1, value2 == 2) do
:ok
end
end