[erlang-questions] Efficiency is passing a functin

33 views
Skip to first unread message

James Rosenblum

unread,
Sep 22, 2012, 8:07:10 PM9/22/12
to erlang-q...@erlang.org
Kind people,

Is there an appreciable difference in these two ways of passing a function?

F = fun(A,B) -> my_function(A,B) end.
lists:map(F, Lst)

vs.

-export([my_function/2]).

lists:map(fun my_function/2, Lst)

Thanks

Michael Truog

unread,
Sep 22, 2012, 9:37:58 PM9/22/12
to James Rosenblum, erlang-q...@erlang.org
From http://www.erlang.org/doc/efficiency_guide/functions.html#id67199
"Calls to local or external functions are the fastest kind of calls."
So, the second solution is best.

Antoine Koener

unread,
Sep 23, 2012, 2:17:36 AM9/23/12
to Michael Truog, erlang-q...@erlang.org
You don't need to export it, if you use it in the same module...

--
Was on the go
_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://erlang.org/mailman/listinfo/erlang-questions

Ulf Wiger

unread,
Sep 23, 2012, 8:55:49 AM9/23/12
to James Rosenblum, erlang-q...@erlang.org

To begin with, your example won't compile, but the question is still valid.

Consider this program:

=================
-module(foldtest).
-export([f1/2, f2/2]).

f1(Acc, Lst) ->
    F = fun(A,B) -> my_function(A,B) end,
    lists:foldl(F, Acc, Lst).

f2(Acc, Lst) ->
    lists:foldl(fun my_function/2, Acc, Lst).

my_function(X, Acc) ->
    [X|Acc].
=================

I believe this illustrates the question, but compiles and runs correctly.

Eshell V5.9  (abort with ^G)
1> foldtest:f1([], [1,2,3]).
[3,2,1]
2> foldtest:f2([], [1,2,3]).
[3,2,1]

Now, let's compile the code with `erlc -S foldtest.erl` (generating ASM code):

{function, f1, 2, 2}.
  {label,1}.
    {line,[{location,"foldtest.erl",4}]}.
    {func_info,{atom,foldtest},{atom,f1},2}.
  {label,2}.
    {allocate,2,2}.
    {move,{x,1},{y,0}}.
    {move,{x,0},{y,1}}.
    {make_fun2,{f,14},0,0,0}.
    {move,{y,0},{x,2}}.
    {move,{y,1},{x,1}}.
    {line,[{location,"foldtest.erl",6}]}.
    {call_ext_last,3,{extfunc,lists,foldl,3},2}.


{function, f2, 2, 4}.
  {label,3}.
    {line,[{location,"foldtest.erl",9}]}.
    {func_info,{atom,foldtest},{atom,f2},2}.
  {label,4}.
    {allocate,2,2}.
    {move,{x,1},{y,0}}.
    {move,{x,0},{y,1}}.
    {make_fun2,{f,12},0,0,0}.
    {move,{y,0},{x,2}}.
    {move,{y,1},{x,1}}.
    {line,[{location,"foldtest.erl",10}]}.
    {call_ext_last,3,{extfunc,lists,foldl,3},2}.

As you can tell, the two alternatives generate identical code.

The fun is compiled into a regular function, albeit with a funny name, and calling it carries the same cost as calling a hand-written function. Actually instantiating a fun context carries a slight overhead depending on the number of variables that need to be imported into the context (in this case, zero). There will be one level of indirection in both cases.

BR,
Ulf W
Ulf Wiger, Co-founder & Developer Advocate, Feuerlabs Inc.



Jim Rosenblum

unread,
Sep 23, 2012, 9:45:02 AM9/23/12
to Ulf Wiger, erlang-q...@erlang.org
Ulf,

How do I reconcile your answer with the previous reference to: http://www.erlang.org/doc/efficiency_guide/functions.html#id67199  which seems to imply that Funs are significantly slower?

Lukas Larsson

unread,
Sep 23, 2012, 10:11:45 AM9/23/12
to Jim Rosenblum, erlang-q...@erlang.org
When you do `fun myfunction` you are creating a fun which points to a
named function. What that text is referencing is that doing

F = fun myfunction/0,
F()

is slower that calling

myfunction()

directly.

So if you want absolute super speed of your lists:fold you should
write the loop yourself and call the function. The speed difference
between the two alternatives is usually not big enough to warrant the
extra code bloat for the minimal speed you gain.

Lukas

Richard O'Keefe

unread,
Sep 23, 2012, 5:56:32 PM9/23/12
to James Rosenblum, erlang-q...@erlang.org

On 23/09/2012, at 12:07 PM, James Rosenblum wrote:
> Is there an appreciable difference in these two ways of passing a function?
>
> F = fun(A,B) -> my_function(A,B) end.
> lists:map(F, Lst)
>
> vs
>
> -export([my_function/2]).
>
> lists:map(fun my_function/2, Lst)

The two are not precisely semantically equivalent.

- The second one exposes a function to external use;
you should generally expose nothing that you don't mean to retain.
+ The second one will work nicely if you hot-reload the module.

But there are two questions I have to ask:

(1) Why not write [my_function(X) || X <- Lst]
and get a direct local call to my_function without exporting
anything extra?

(2) Why not *measure* the three versions and see whether the
difference is of any practical significance in the context
of everything else going on in the real program?
Reply all
Reply to author
Forward
0 new messages