while testing a function of mine I’ve stumbled upon a strange issue - when I make a mistake in an anonymous function it might try to call the parent function recursively and throw a confusing BadArityError. Here is an example (can be pasted in a test file):
def external_fun(text) do
dummy_list = [[one: "1", two: "2"], [one: "3", two: "4"], [one: "5", two: "6"]]
text = Enum.reduce(dummy_list, text, fn(map, text) ->
text = text <> Keyword.get(map, :one)
text
end)
IO.inspect text
end
test "dev", %{conn: conn} do
external_fun("Test")
end
This should be green and give a “Test135” in console. Now when I make a mistake in the anonymous function by losing the second parameter like that:
text = Enum.reduce(dummy_list, text, fn(map) ->
text = text <> Keyword.get(map, :one)
text
end)
I get a ** (BadArityError) #Function ... external_fun/1> with arity 1 called with 2 arguments ([one: "1", two: "2"], "Test") which is really confusing for such a “silly” mistake.
What actually happened? Why does reduce’s callback reaches to the parent function?
Is there a way to prevent such issues by changing my coding style (similar to using parentheses more often), should I maybe prefer named functions as callbacks? I’ve just spent about 20 minutes solving this issue and would like to make the most of it in the future
@sysashi@hubertlepicki that’s it, it actually makes sense, just added few dummy params to the external function to be sure, arity is still stated as 1.
also you are reusing the “text” as variable name in outer scope as in inner scope of anonymous function. This may be confusing for the reader of the code. I tend to use different names even if technically nothing wrong happens, just for readability - to distinguish those.
@hubertlepicki true, it has to do with me having to simplify my use case quickly to post here, if I wrote it from the beginning I’d probably make it sexier