Reputation: 14539
In ExProf, Elixir function names are printed out as what I assume is their Erlang names, after compilation. One example is
Enum.reduce/3
which is printed as
'Elixir.Enum':'-reduce/3-lists^foldl/2-0-'/3
How do I parse this string? Where does the -lists^foldl/2-0-
part come from? Why are there multiple /3
? Why are some names -
prefixed? What does the ^
mean? Why the 2-0-
?
Upvotes: 8
Views: 1020
Reputation: 222388
How do I parse this string?
'Elixir.Enum':'-reduce/3-lists^foldl/2-0-'/3
is the function reference syntax in Erlang referring to a function named -reduce/3-lists^foldl/2-0-
in the module Elixir.Enum
, with arity 3, similar to &Enum."-reduce/3-lists^foldl/2-0-"/3
in Elixir.
Where does the
-lists^foldl/2-0-
part come from?
The -$fn/$arity-$something-$count-
is the name returned by Erlang in stacktraces (and apparently profiling output) for an anonymous function defined inside $fn/$arity
. Normally, you would see something like -main/0-fun-0-
, i.e. $something == "fun"
, for example, this:
defmodule Foo do
def main do
try do
(fn -> raise("foo") end).()
rescue
_ -> IO.inspect System.stacktrace
end
end
end
prints:
[{Foo, :"-main/0-fun-0-", 0, [file: 'foo.ex', line: 4]},
{Foo, :main, 0, [file: 'foo.ex', line: 4]},
{:erl_eval, :do_apply, 6, [file: 'erl_eval.erl', line: 670]},
{:elixir, :erl_eval, 3, [file: 'src/elixir.erl', line: 223]},
{:elixir, :eval_forms, 4, [file: 'src/elixir.erl', line: 211]},
{Code, :eval_string, 3, [file: 'lib/code.ex', line: 168]},
{Kernel.CLI, :wrapper, 1, [file: 'lib/kernel/cli.ex', line: 437]},
{Enum, :"-map/2-lists^map/1-0-", 2, [file: 'lib/enum.ex', line: 1184]}]
It's just that you're less likely to see -fun-
ones in Elixir's default error messages because they're normalized, to anonymous fn/0 in Foo.main/0
in this case (this is why I printed the stacktrace above by calling System.stacktrace/0
explicitly).
So where does lists^foldl/2
come from? That's generated by sys_core_fold_lists
, a module called by sys_core_fold
for modules defining inline_list_funcs
compile attribute (the Enum
module in Elixir does do that), which "Inlines high order lists functions from the lists module". This inlining also gives the name "lists^foldl/2" to the anonymous function instead of just being "fun".
Here's a simple demo:
defmodule Fold do
@compile :inline_list_funcs
def main do
sum([1, 2, 3])
end
def sum(list) do
:lists.foldl(fn a, b -> raise "foo" end, 0, list)
end
end
Fold.main
With @compile :inline_list_funcs
, the output is:
** (RuntimeError) foo
fold.exs:9: anonymous fn/2 in Fold.sum/1
fold.exs:9: Fold."-sum/1-lists^foldl/2-0-"/3
(elixir) lib/code.ex:363: Code.require_file/2
and without it, the output is:
** (RuntimeError) foo
fold.exs:9: anonymous fn/2 in Fold.sum/1
(stdlib) lists.erl:1263: :lists.foldl/3
(elixir) lib/code.ex:363: Code.require_file/2
With that attribute, we don't have any stacktrace entry for the lists
module, even though we're explicitly calling :lists:foldl
.
Why are there multiple
/3
?
That seems to be a side effect of Erlang including the arity of the current function when naming an anonymous function.
Why are some names
-
prefixed?
Explained above.
What does the
^
mean?
It's just a name that sys_core_fold_lists:call/4
chose.
Why the
2-0-
?
2
comes from sys_core_fold_lists:call/4
. 0
is referred to as "count" in Exception.format_mfa/3
but I'm not sure what that means.
Upvotes: 1
Reputation: 151
It is a generated name for some 'anonymous' function inside Enum.reduce
implementation. I assume this function is defined inline and passed as an argument to the lists:foldl
, hence the name. AFAIK such names are generated not by Elixir but by Erlang itself.
Upvotes: 0