tags:

views:

628

answers:

4

I want to call xyz with the name of a function to be invoked.

-module(sample).
-export([xyz/1]).

xyz(Name) -> Name().

p() -> "you called p".
g() -> "you called g".

But I get the following error:

1> c(sample.erl).
./sample.erl:6: Warning: function p/0 is unused
./sample.erl:7: Warning: function g/0 is unused
{ok,sample}
2> sample:xyz('p').
** exception error: bad function p
     in function  sample:xyz/1
3>
+7  A: 

It is correct that you have to export p and g. You can then use apply/3 to call it.

erlang:apply(sample, p, [])

Only fun-values are usable with the Fun(...) syntax. You are passing in an atom-value. An atom is a 'bad function' as the error message go. You could do something similar to

xyz(p) -> fun p/0;
xyz(g) -> fun g/0.

Then go ahead and call

Fun = xyz(p),
Fun()
Christian
Thanks. I now have this:-module(sample).-export([xyz/1, p/0, g/0]).xyz(Name) -> apply(sample, Name, []).p() -> "you called p".g() -> "you called g".and I am able to do:26> c(sample.erl).{ok,sample}27> sample:xyz('p')."you called p"28> sample:xyz(p)."you called p"29> sample:xyz('g')."you called g"30> sample:xyz(g)."you called g"But isn't there a way of not exporting these functions? I don't want it to be visible to module users. Can't seem to get it working with apply/2 either. Of course, I am an erlang newbie
bagheera
You either hard-code your call-mapping with pattern matching, or export your functions.
Zed
The only way to 'leak' an unexported function is to return a fun value that refers to it. Just like my explicit xyz/1 function that returns a fun value.
Christian
+4  A: 

Pattern match is the idiom to use:

-module(sample).
-export([xyz/1]).

xyz(p) -> p();
xyz(q) -> g().

p() -> "you called p".
g() -> "you called g".

If you want to be dynamic you can use a gen_event server.

Essentially what this is is a server that holds a state which consists of key/function pair like so:

[{p, #func1},
 {g, #func2},
 {..., ...},
 ...]

You can then essentially bind events to functions. (there is, needless to say, a bit more to it than that.

Gordon Guthrie
while this is technically one way to do it I think the question is more geared to the mechanics in erlang the language to dynamically call a function. The apply function is the answer he's looking for.
Jeremy Wall
+4  A: 
-module(sample).
-export([xyz/1, p/0, g/0]).

xyz(Name) -> ?MODULE:Name().

p() -> "you called p".
g() -> "you called g".


1> sample:xyz(p).
"you called p"
Zed
That's pretty cool. Where can I read about "?MODULE" ? Now if only we could do away with exporting p and q.
bagheera
Here are the predefined macros: http://erlang.org/doc/reference_manual/macros.html#7.3 . Unfortunately Erlang only has "public" and "private" visibility, but no protected and package protected. So you either export it, or "hardcode" the calls.
Zed
But why am I not required to export in case of a statically bound call xyz(Name)-> p(). and required to export when it is dynamically bound? Thinking in terms of "private" visibility, I am in private scope, am I not?
bagheera
If you go as Gordon or Christian suggested, then you don't need to export them. As a trade-off, if you later add an s() function, you will need to modify the code of xyz() as well.If you go with the dynamic solution, you will need to export the functions. In your code documentation you can clearly state that p and g are internal exported functions, and should not be called. Also, in a functional language someone calling functions just-for-fun should not cause you a major problem.
Zed
A: 

Another way to look at it is that (depending on the problem you're solving) dynamic calls to functions isn't necessarily the right approach. Given that processes and message passing are the way you organize your code in Erlang since it's a "concurrency oriented language", maybe you could just use message passing with a selective receive rather than mimicking idioms of a sequential language? Send a message for what you want and get the custom reply based on that. It's about the result of each function, not the function itself, after all. (Plus there's the flexibility and scalability of message passing, etc.)

Although processes aren't totally free compared to calling from a library module, Erlang-level processes are dirt cheap (especially if the message communication is within the same node). They're not OS-level processes. The overhead would be comparable (or better) to dynamic function calls and object instantiation in heavier scripting languages.

Rob W