Need I export all functions in Erlang shell? - erlang

I have these code
start() ->
spawn(?MODULE, init, [self()]).
init(From) ->
spawn(?MODULE, broadcast, []).
broadcast() ->
Msg = "helloworld",
timer:sleep(10000),
broadcast().
When I test these code in Erlang shell, it give me undef error, I need to export broadcast function, I am just refuse

Code
spawn(?MODULE, init, [self()]).
means you will spawn process which initial call will be ?MODULE:init(self()) or more precisely equivalent of apply(?MODULE,init,[self()]). ?MODULE is macro evaluated to current module name but anyway It is external function call so this function have to be exported even there is ?MODULE used. In contrary
spawn(fun() -> init(self()) end).
is spawn with initial call to the func fun() -> init(self()) end which calls init/1 with result of function self(). It is local call which means init/1 may not be exported. There is another issue with it when self() is performed inside new process so you have to write
Self = self(), spawn(fun() -> init(Self) end).
to achieve same effect as in spawn(?MODULE, init, [self()]) where self() is evaluated as parameter of spawn/3.

well, the function broadcast is executed in a process. This function must therefore be accessible to all processes. Even though the same piece of source code, in the same module, spawns a process which goes to execute a function from the same module, that function must be exported out of that module to make it accessible.
That brings me to the difference between spawn(fun() -> broadcast() end). and spawn(?MODULE, broadcast, []). The later is called Spawning with MFA. In this method, the function must be exported out of the module so that it can be executed. The former is however unique, its a fun.
To understand this method: spawn(fun() -> broadcast() end)., we need to compare it with this one: spawn(fun() -> ?MODULE:broadcast() end). . Now, lets talk about the later of the two
spawn(fun() -> ?MODULE:broadcast() end). Now, here, if the function broadcast IS NOT exported in the module: ?MODULE, the process will crash. Note that in this case, the function is in the very module in which this piece of source code is written. spawn(fun() -> broadcast() end).In this case, the function must be in the very module in which this piece of source code is written. However, my thinking is this, the compiler converts this to the one above so that the spawned process is told that the function you are looking for is in module ?MODULE.I am not really a guru at compilers or run time systems, but i guess you will use this answer. My Strong advice is that in most of your source code, use this spawn(fun() -> ?MODULE:broadcast() end). or spawn(fun() -> some_module:broadcast() end). even though the piece of code or the function resides in that same very module than this: spawn(fun() -> broadcast() end).. From my personal experience the code becomes manageable and understandable. I get this nice illusion that a spawned process has to go and find the function from the specified module, and then execute with the given arguments.

Look more carefully at the warnings:
test.erl:8: Warning: function init/1 is unused
test.erl:8: Warning: variable 'From' is unused
test.erl:11: Warning: function broadcast/0 is unused
test.erl:12: Warning: variable 'Msg' is unused
The compiler thinks that your other functions are unused and never compiles them. Try this instead:
start() ->
spawn(fun() -> init(self()) end).
init(From) ->
spawn(fun() -> broadcast() end).

Related

Getting to grips with Erlang messages

I'm still trying to come to grips with Erlang messages, and while playing around with it, I came up with this case. It seems like it should work, but it just hangs indefinitely.
Can someone who is more used to Erlang please explain what I am doing wrong? And yes, I am aware that I don't even look at what is returned. This is the result of trying to reduce the code to isolate the problem.
-module(test).
-export([caller/2]).
callee(V1, V2, From) ->
From ! {V1, V2}.
caller(V1, V2) ->
spawn(fun() ->
callee(V1, V2, self()) end),
receive
_ ->
{V1, V2}
end.
If you assign the result of self() to a variable outside the function in the call to spawn and then pass in that variable instead of the literal self() then the message sent in callee will correctly be sent to the process running caller (the process waiting on receive).
This bit will help you understand where is the problem.
1> Self = self(), spawn(fun() -> io:format("Self: ~p, self():~p ~n", [Self, self()]) end).
Self: <0.83.0>, self():<0.85.0>
<0.85.0>

MongooseIM simple module event not getting handled

I am new in erlang and ejabbered/mongooseIM. I am trying to write a very simple mongoose module that will add an extra child element to the packets before sending. Below is my code:
-module(mod_test).
-behavior(gen_mod).
-export([start/2, stop/1]).
-export([add_child/1]).
-include("ejabberd.hrl").
start(Host, Opts) ->
ejabberd_hooks:add(filter_packet, Host, ?MODULE, add_child, 0),
?DEBUG(" MOD_TEST Started",[]),
ok.
stop(Host) ->
ejabberd_hooks:delete(filter_packet, Host, ?MODULE, add_child, 0),
ok.
add_child({From, To, XML} = Packet) ->
Tag = {"a","b"},
NewPacket = xml:append_subtags(Packet, [Tag]),
?INFO_MSG(" To party: ~p~n",[To]),
NewPacket.
I can compile the code with few warnings
mod_test.erl:3: Warning: behaviour gen_mod undefined
mod_test.erl:11: Warning: variable 'Opts' is unused
mod_test.erl:20: Warning: variable 'From' is unused
mod_test.erl:20: Warning: variable 'XML' is unused
Then when I add the module and run it it gets started but it doesnt make any changes to the packets and doesnt generate any logs either.
Another issue is, if I add a log within my start function, it gets compiled but I see errors while starting the module
2015-03-03 16:36:34.772 [critical] <0.200.0>#gen_mod:start_module:94 Problem starting the module mod_test for host <<"localhost">>
options: []
error: undef
[{lager,info,[" mod_test starting ...",[[]]],[]},
{mod_test,start,2,[{file,"mod_test.erl"},{line,13}]},
{gen_mod,start_module,3,[{file,"src/gen_mod.erl"},{line,83}]},
{lists,foreach,2,[{file,"lists.erl"},{line,1336}]},
{ejabberd_app,start,2,[{file,"src/ejabberd_app.erl"},{line,69}]},
{application_master,start_it_old,4,
[{file,"application_master.erl"},{line,272}]}]
2015-03-03 16:36:34.773 [critical] <0.200.0>#gen_mod:start_module:99 ejabberd initialization was aborted because a module start failed.
The trace is [{lager,info,[" mod_test starting ...",[[]]],[]},{mod_test,start,2,[{file,"mod_test.erl"},{line,13}]},{gen_mod,start_module,3,[{file,"src/gen_mod.erl"},{line,83}]},{lists,foreach,2,[{file,"lists.erl"},{line,1336}]},{ejabberd_app,start,2,[{file,"src/ejabberd_app.erl"},{line,69}]},{application_master,start_it_old,4,[{file,"application_master.erl"},{line,272}]}].
Crash dump was written to: erl_crash.dump
Problem starting the module mod_test for host <<"localhost">>
options: []
error: undef
[{lager,info,[" mod_xyz starting ...",[[]]],[]},
{mod_test,start,2,[{file,"mod_timetagg
What wrong am I doing?
So your example is actually a bit tricky, because of how the filter_packet hook works. You picked the worst hook to register for on your first attempt ;)
If you look into ejabberd_router:do_route, you'll see that filter_packet is run without a Host parameter -- it is a global hook, so when you register your add_child function for a particular Host, it will essentially be ignored.
Try the following:
-module(mod_test).
-behavior(gen_mod).
-export([start/2, stop/1]).
-export([add_child/1]).
-include_lib("ejabberd/include/ejabberd.hrl").
-include_lib("exml/include/exml.hrl").
start(Host, Opts) ->
ejabberd_loglevel:set_custom(?MODULE, 5),
ejabberd_hooks:add(filter_local_packet, Host, ?MODULE, add_child, 1),
?DEBUG(" MOD_TEST Started",[]),
ok.
stop(Host) ->
ejabberd_hooks:delete(filter_local_packet, Host, ?MODULE, add_child, 1),
ok.
add_child({From, To, Element} = HookData) ->
?DEBUG("Filtering ~p~n", [HookData]),
case Element#xmlel.name of
<<"message">> ->
Tag = #xmlel{name = <<"added-tag">>, attrs = [], children = []},
NewElement = xml:append_subtags(Element, [Tag]),
?DEBUG("will return new el: ~p", [NewElement]),
{From, To, NewElement};
_ ->
?DEBUG("will pass old el: ~p", [Element]),
HookData
end.
Registering for filter_local_packet on your given Host will now work, and all incoming stanzas will be passed to your function. It is important to remember that adding spurious tags to all stanzas may break things, so the above code will only add a <added-tag> element to <message> stanzas.
Use the example above and work from there.
Good luck!
The error is undef, which means that a function was called that isn't defined/exported. The stacktrace shows that the function in question is lager:info/2.
Lager (the logging library that handles your ?INFO_MSG) has a special quirk in that your code would call non-existent functions, but the code gets transformed by a parse transform before being compiled. It looks like this didn't happen for you.
The rebar.config file in apps/ejabberd in the MongooseIM tree contains {parse_transform, lager_transform} in erl_opts, which asks the compiler to apply the parse transform. I'd suggest putting mod_test.erl into apps/ejabberd/src and build the entire MongooseIM tree; that would ensure that your file gets built with the correct options.

How to test gen server in erlang?

I am a beginner with erlang, and i write a basic gen server program as follows, I want to know, how to test the server so i can know it works well.
-module(gen_server_test).
-behaviour(gen_server).
-export([start_link/0]).
-export([alloc/0, free/1]).
-export([init/1, handle_call/3, handle_cast/2]).
start_link() ->
gen_server:start_link({local, gen_server_test}, ch3, [], []).
alloc() ->
gen_server:call(gen_server_test, alloc).
free(Ch) ->
gen_server:cast(gen_server_test, {free, Ch}).
init(_Args) ->
{ok, channels()}.
handle_call(alloc, _From, Chs) ->
{Ch, Chs2} = alloc(Chs),
{reply, Ch, Chs2}.
handle_cast({free, Ch}, Chs) ->
io:format(Ch),
io:format(Chs),
Chs2 = free(),
{noreply, Chs2}.
free() ->
io:format("free").
channels() ->
io:format("channels").
alloc(chs) ->
io:format("alloc chs").
BTW: The program can be compiled, and it is not a good program, I just want to print something to make sure it works :)
The beauty of a gen_server implementing module is that it is just a callback module. One need not even have to spawn the underlying gen_server process to test it.
All you need to do is have your test framework (usually eunit) to invoke all the handle_call/cast/info functions by injecting it with different inputs (different gen_server states, different input messages) etc. and ensure it returns the correct response tuple (for eg. {reply, ok, NewState} or {noreply, NewState} etc.)
Ofcourse, this wouldnt work perfectly if your callback functions arn't pure functions. For eg., in your handle_call function, if you are sending a message to another process for eg., or if you are modifying an ets table. In which case, you have to ensure that all the required processes and tables are pre-created before running the test.
You could try one of the following:
Use the erlang shell and invoke the commands manually. Make sure the source or .beam file is in the Erlang path (parameter -pz, like this: erl -pz <path here>)
Write an EUnit test case
PS: I think you have an error in your code, because you seem to start the module ch3 as the server, not the gen_server_test module.

Basic Erlang Question

I have been trying to learn Erlang and came across some code written by Joe Armstrong:
start() ->
F = fun interact/2,
spawn(fun() -> start(F, 0) end).
interact(Browser, State) ->
receive
{browser, Browser, Str} ->
Str1 = lists:reverse(Str),
Browser ! {send, "out ! " ++ Str1},
interact(Browser, State);
after 100 ->
Browser ! {send, "clock ! tick " ++ integer_to_list(State)},
interact(Browser, State+1)
end.
It is from a blog post about using websockets with Erlang: http://armstrongonsoftware.blogspot.com/2009/12/comet-is-dead-long-live-websockets.html
Could someone please explain to me why in the start function, he spawns the anonymous function start(F, 0), when start is a function that takes zero arguments. I am confused about what he is trying to do here.
Further down in this blog post (Listings) you can see that there is another function (start/2) that takes two arguments:
start(F, State0) ->
{ok, Listen} = gen_tcp:listen(1234, [{packet,0},
{reuseaddr,true},
{active, true}]),
par_connect(Listen, F, State0).
The code sample you quoted was only an excerpt where this function was omitted for simplicity.
The reason for spawning a fun in this way is to avoid having to export a function which is only intended for internal use. One problem with is that all exported functions are available to all users even if they only meant for internal use. One example of this is a call-back module for gen_server which typically contains both the exported API for clients and the call-back functions for the gen_server behaviour. The call-back functions are only intended to be called by the gen_server behaviour and not by others but they are visible in the export list and not in anyway blocked.
Spawning a fun decreases the number of exported internal functions.
In Erlang, functions are identified by their name and their arity (the number of parameters they take). You can have more than one function with the same name, as long as they all have different numbers of parameters. The two functions you've posted above are start/0 and interact/2. start/0 doesn't call itself; instead it calls start/2, and if you take a look further down the page you linked to, you'll find the definition of start/2.
The point of using spawn in this way is to start a server process in the background and return control to the caller. To play with this code, I guess that you'd start up the Erlang interpreter, load the script and then call the start/0 function. This method would then start a process in the background and return so that you could continue to type into the Erlang interpreter.

Erlang - spawning processes and passing arguments

I keep running into this. I want to spawn processes and pass arguments
to them without using the MFA form (module/function/arguments), so
basically without having to export the function I want to spawn with
arguments. I've gotten around this a few times using closures(fun's)
and having the arguments just be bound values outside the fun(that I then reference inside the fun), but its
limiting my code structure... I've looked at the docs and spawn only
has the regular spawn/1 and the spawn/3 form, nothing else...
I understand that code reloading in spawned processes is not possible without the use of the MFA form but the spawned processes are not of the long running nature and finish relatively quickly so that's not an issue (I also want to contain all the code in one module-level function with sub-jobs being placed in funs inside that function).
much appreciated
thanks
actually Richard pointed me in the right direction to take to avoid the issue nicelly (in a reply to the same post I put up on the Erlang GoogleGroups):
http://groups.google.com/group/erlang-programming/browse_thread/thread/1d77a697ec67935a
His answer:
By "using closures", I hope you mean something like this:
Pid = spawn(fun () -> any_function(Any, Number, Of, Arguments) end)
How would that be limiting to your code structure?
/Richard
thank you for promptly commenting you my question. Much appreciated
Short answer: you can't. Spawn (in all it's varying forms) only takes a 0-arity function. Using a closure and bringing in bound variables from the spawning function is the way to go, short of using some sort of shared data store like ETS (which is Monster Overkill).
I've never found using a closure to severely hamper my code structure, though; can you give an example of the problems you're having, and perhaps someone can tidy it up for you?
This is an old question but I believe it can be properly answered with a bit of creativity:
The goal of the question is to
Invoke a function
With the following limits;
No M:F/A formatting
No exporting of the Invoked function
This can be solved in the following;
Using the 1st limitation leads us to the following solution:
run() ->
Module = module,
Function = function,
Args = [arg1, arg2, arg3],
erlang:spawn(Module, Function, Args).
In this solution however, the function is required to be exported.
Using the 2nd limitation (No exporting of the Invoked function) alongside the 1st leads us to the following solution using conventional erlang logic:
run() ->
%% Generate an anonymous fun and execute it
erlang:spawn(fun() -> function(arg1, arg2, arg3) end).
This solution generates Anonymous Funs every execution which may or may not be wanted based on your design due to the extra work that the Garbage Colelctor will need to perform (note that, generally, this will be neglible and issues will potentially only be seen in larger systems).
An alternative way to write the above without generating Anonymous Funs would be to spawn an erlang:apply/2 which can execute functions with given parameters.
By passing a Function Ref. to erlang:apply/2, we can reference a local function and invoke it with the given arguments.
The following implements this solution:
run() ->
%% Function Ref. to a local (non-exported) function
Function = fun function/arity,
Args = [arg1, arg2, arg3],
erlang:spawn(erlang, apply, [Function, Args]).
Edit: This type of solution can be found within the Erlang Src whereby erlang:apply/2 is being called to execute a fun() with args.
%% https://github.com/erlang/otp/blob/71af97853c40d8ac5f499b5f2435082665520642/erts/preloaded/src/erlang.erl#L2888%% Spawn and atomically set up a monitor.
-spec spawn_monitor(Fun) -> {pid(), reference()} when
Fun :: function().
spawn_monitor(F) when erlang:is_function(F, 0) ->
erlang:spawn_opt(erlang,apply,[F,[]],[monitor]);
spawn_monitor(F) ->
erlang:error(badarg, [F]).
first, there is no code and we can't help you a lot, so the best way to control your functions and their args with your spawned processes is to spawn the process with a receive function then you will be in contact with your process across the send and receive method, try:
Pid=spawn(Node, ModuleName, functionThatReceive, [])
%%or just spawn(ModuleName....) if the program is not %%distributed
Pid ! {self(), {M1, f1, A1}},
receive
{Pid, Reply} ->Reply
end,
Pid ! {self(), {M2, f2, A2}},
receive
{Pid, Reply} ->Reply
end,
.......
functionThatReceive() ->
receive
{From, {M1, f1, A1}} ->From ! {self(), doSomething1} ;
{From, {M2, f2, A2}} ->From ! {self(), doSomething2}
end.

Resources