Quantcast

Funs behaving differently after native compilation

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Funs behaving differently after native compilation

Joel Reymont
Folks,

My funs seem to behave differently when the beams are compiled to  
native code.

Is there an explanation to this? I am passing indeed passing funs as  
{M, F} and then calling them as per the code below.

Why does it work when the code is byte-compiled and how do I work  
around these errors?

monitor(self(), Sock, {gen_udp, close})

monitor(Sock, Closer) ->
     receive
        {'DOWN', _, process, _, _} ->
            Closer(Sock);
        Any ->
            io:format("Monitor: Unknown:~n~p~n", [Any]),
            monitor(sock, Closer)
     end.

My make file:

{'*',[native]}.

The errors that I get when my code is compiled to native:

=ERROR REPORT==== 12-Jan-2006::15:42:25 ===
Error in process <0.31.0> with exit value: {{'EXIT',{{badfun,
{randomplay,script}},[]}},[]}

=ERROR REPORT==== 12-Jan-2006::15:42:26 ===
Error in process <0.30.0> with exit value: {{'EXIT',{{badfun,
{lobbybot,script}},[]}},[]}

=ERROR REPORT==== 12-Jan-2006::15:42:26 ===
Error in process <0.32.0> with exit value: {{badfun,{gen_udp,close}},[]}

        Thanks, Joel

--
http://wagerlabs.com/

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Funs behaving differently after native compilation

Joel Reymont
I could certainly change things to

     Closer = fun(Sock) -> gen_udp:close(Sock) end,
     monitor(self(), Sock, Closer),

for this particular case but I'm also passing the name of the module  
from the command like to invoke the script function in it.

I don't see how I can construct a real fun from an atom that is the  
module name.

On Jan 12, 2006, at 4:00 PM, Joel Reymont wrote:

> Folks,
>
> My funs seem to behave differently when the beams are compiled to  
> native code.
>
> Is there an explanation to this? I am passing indeed passing funs  
> as {M, F} and then calling them as per the code below.
>
> Why does it work when the code is byte-compiled and how do I work  
> around these errors?
>
> monitor(self(), Sock, {gen_udp, close})
>
> monitor(Sock, Closer) ->
>     receive
> {'DOWN', _, process, _, _} ->
>    Closer(Sock);
> Any ->
>    io:format("Monitor: Unknown:~n~p~n", [Any]),
>    monitor(sock, Closer)
>     end.

--
http://wagerlabs.com/





Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Funs behaving differently after native compilation

Joel Reymont
I worked around this by calling apply(Module, ...). Apparently {M, F}  
is deprecated.

Still, it's interesting that no error is reported and everything  
works fine when byte-compiled.

On Jan 12, 2006, at 4:03 PM, Joel Reymont wrote:

> I could certainly change things to
>
>     Closer = fun(Sock) -> gen_udp:close(Sock) end,
>     monitor(self(), Sock, Closer),
>
> for this particular case but I'm also passing the name of the  
> module from the command like to invoke the script function in it.
>
> I don't see how I can construct a real fun from an atom that is the  
> module name.

--
http://wagerlabs.com/





Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Funs behaving differently after native compilation

Richard Carlsson
In reply to this post by Joel Reymont
Joel Reymont wrote:

> I could certainly change things to
>
>     Closer = fun(Sock) -> gen_udp:close(Sock) end,
>     monitor(self(), Sock, Closer),
>
> for this particular case but I'm also passing the name of the module
> from the command like to invoke the script function in it.
>
> I don't see how I can construct a real fun from an atom that is the
> module name.

You could do something like this:

   foo({M,F}) ->
     Closer = fun(Sock) -> M:F(Sock) end,
     monitor(self(), Sock, Closer)

or if only the module name is changing:

   foo(M) ->
     Closer = fun(Sock) -> M:close(Sock) end,
     monitor(self(), Sock, Closer)

etc.

The OTP guys recently added dynamic-lookup "funs" on the form
'fun foo:bar/2', but it seems that you cannot create them using
variables, as in "fun M:F/A" (which would be handy in my opinion).
Perhaps this can be added? The advantage over tuples is that
is_function/1 yields true for the funs, and that there is no
confusion about the arity of the called function. (E.g., if
you use {M,F}, and then change the number of arguments, but
forget to update some call site, it might continue to "work"
by calling the wrong function. Not good.) Also, analyses like
those done by Dialyzer are more easily foiled by passing around
atoms - or (shudder!), even manipulating strings and converting
them to atoms and finally using those atoms to call a function!

        /Richard

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Funs behaving differently after native compilation

Richard Carlsson
In reply to this post by Joel Reymont
Joel Reymont wrote:
> I worked around this by calling apply(Module, ...). Apparently {M, F}
> is deprecated.

Don't do that. Calling apply is generally much more inefficient,
since it must traverse a list to push arguments on the stack.
Unless your argument lists really vary in length (and then you
should stop and ask yourself what the heck you are doing...),
it is both faster and cleaner to just do Module:Function(...).

        /Richard

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Funs behaving differently after native compilation

Mikael Pettersson-2
In reply to this post by Joel Reymont
Joel Reymont writes:
 > Folks,
 >
 > My funs seem to behave differently when the beams are compiled to  
 > native code.
 >
 > Is there an explanation to this? I am passing indeed passing funs as  
 > {M, F} and then calling them as per the code below.
 >
 > Why does it work when the code is byte-compiled and how do I work  
 > around these errors?
 >
 > monitor(self(), Sock, {gen_udp, close})
 >
 > monitor(Sock, Closer) ->
 >      receive
 > {'DOWN', _, process, _, _} ->
 >    Closer(Sock);
 > Any ->
 >    io:format("Monitor: Unknown:~n~p~n", [Any]),
 >    monitor(sock, Closer)
 >      end.
 >
 > My make file:
 >
 > {'*',[native]}.
 >
 > The errors that I get when my code is compiled to native:
 >
 > =ERROR REPORT==== 12-Jan-2006::15:42:25 ===
 > Error in process <0.31.0> with exit value: {{'EXIT',{{badfun,
 > {randomplay,script}},[]}},[]}

A simpler test module:
==snip==
-module(bar).
-compile(export_all).

test1() -> bar1({?MODULE,f}, 42).
test2() -> bar2({?MODULE,f}, 42).
test3() -> bar3({?MODULE,f}, 42).

bar1(MF, X) -> MF(X).
bar2(MF, X) -> apply(MF, [X]).
bar3({M,F}, X) -> M:F(X).

f(42) -> ok.
==snip==

In this module, test1() to test3() all work in BEAM mode,
but only test2() and test3() work after compilation to native code:
bar:test1() results in a badfun exception.

HiPE could allow bar:test1() to work. The reason it doesn't is
largely political: some people have strong opinions against the
old-fashioned {M,F} functions, and since there are alternatives,
there have been little incentive to extend the compiler to support
them. A secondary reason is that it would cause code bloat for all
MF(X)-like expressions.

/Mikael
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Funs behaving differently after native compilation

Joel Reymont
In reply to this post by Richard Carlsson
Thank you Richard!

On Jan 12, 2006, at 4:34 PM, Richard Carlsson wrote:

> You could do something like this:
>
>    foo({M,F}) ->
>      Closer = fun(Sock) -> M:F(Sock) end,
>      monitor(self(), Sock, Closer)

--
http://wagerlabs.com/





Loading...