defmodule Fn do
def f1(g, x) do
fun = fn
# We'll mutate the function patterns
value when is_integer(value) -> g.(value)
end
fun.(x)
end
def f2(x) do
fun = fn
# We'll mutate the function patterns
value when is_integer(value) -> value
end
fun.(x)
end
end
then you would have:
iex(49)> Fn.f1(fn x -> x end, :invalid)
** (CaseClauseError) no case clause matching: {:invalid}
(darwin 0.1.0) lib/darwin.ex:28: Fn.f1/2
iex(49)> Fn.f2(:invalid)
** (FunctionClauseError) no function clause matching in Fn.f2/1
The following arguments were given to Fn.f2/1:
# 1
:invalid
Attempted function clauses (showing 1 out of 1):
def f2(x)
(darwin 0.1.0) lib/darwin.ex:37: Fn.f2/1
In one case you get a FunctionClauseError and in another case you get a CaseClauseError. Is this supposed behaviour? I came up with this when testing my mutation testing framework, so it’s definitely a weird corner case, but I wonder if the Elixir core team would like to look into it.
I think this is because the fun inside f1 is immediately invoked with arguments that are in scope so it is transformed into a case expression by the compiler. I know such optimization exists but I cannot find the article or changelog where it is described.