Trying to execute a function using a timer but the compiler says the function is unused - erlang

I was trying to execute a function a few seconds in the future by using timer:apply_after() but when I tried to compile the module it threw an error.
For example, say I have a module with two functions - one that prints an age, and another that uses a timer to execute it at a future time.
-module(test).
-export([main/0]).
print_age(Age) ->
io:format("Your age: ~p~n", [Age]).
main() ->
timer:apply_after(2000, test, print_age, [20]).
When I compile the module, I get:
> c(test).
test.erl:4: Warning: function print_age/1 is unused
{ok,test}

Although there's nothing in the timer docs to indicate it, the function must be exported in order for the timer to execute it:
-module(test).
-export([main/0, print_age/1]).
print_age(Age) ->
io:format("Your age: ~p~n", [Age]).
main() ->
timer:apply_after(2000, test, print_age, [20]).
One could get around the compiler error by adding -compile({nowarn_unused_function, {print_age,1}}). to the top of the module, but then it'll turn into a runtime error when the timer attempts to execute the function:
=ERROR REPORT==== 6-Jun-2018::13:37:14 ===
Error in process <0.89.0> with exit value:
{undef,[{test,print_age,[20],[]}]}
I don't know all the inner details of how timer works, but this answer indicates that it's running in a gen_server in a separate process.
The timer module is a standard gen_server running in a separate process. All the function in the timer module are public interfaces that execute a hidden gen_server:call or gen_server:cast to the timer server. This is a common usage to hide the internal of a server and allow further evolutions without impact on existing applications.
It makes sense I guess, since the current process must be able to continue executing code, and which function to execute must be stored safely somewhere until the delay is passed. And since one module can only access a function in another module if it's been exported, the function to execute must be exported too.

Related

Unable to spawn process on another node in Erlang

When I try to create a new process on separate node using
Pid = spawn(mynode, mymodule, myfunction, [self()])
(myfunction/1 is exported), I get this error:
Error in process <0.10.0> on node 'no#de1' with exit value:
{undef,[{mymodule, myfunction, [<33.64.0>], []}]}
I tried to set -compile(export_all) flag, but assuming the additional braces in error log, this is not the case.
I don't know what causes the error and I have no clue what to do.
The error you get is saying “There is no module ‘mymodule’ and/or no function ‘mymodule:myfunction/1’”.
This means mymodule is not loaded in the code server of your separate node.
To load mymodule's code there you need something like this snippet or this function
Did you check that the module mymodule is in the path of no#de1?
When you spwan a process using spawn(mynode, mymodule, myfunction, [self()]), the VM needs to load the code before executing it.
If you use a high order function (a fun) in this way spawn(Node, Fun), then in is not more necessary to have the code in the path (but beware that any call to a function in the function definition need to be solved on the remote node)
go to no#de1 and run m(mymodule). It should clarify if the module is loadable and which functions does export.
also: check if the other node is reachable. Do a net_adm:ping on it.

Register and spawn_link in Erlang not working together

I have a process running on node2. Can I register this process using register/2 on node1? Basically I am trying to do this:
register(process_name, spawn_link(node2, module, function, [Arg1, Arg2]))
I get this error:
** exception error: bad argument
in function register/2
called as register(process_name, <5902.92.0>)
When I register a process local to node1, this works perfectly fine. I could not find any documentation which prevents registration of processes of other nodes.
Thanks.
Actually it is well documented, and the expected behaviour as register() is for local process registration.
http://www.erlang.org/doc/man/erlang.html#register-2
Failure: badarg if PidOrPort is not an existing, local process or port, [...]
If you want global registration across your cluster, read http://erlang.org/doc/man/global.html
Note that if you use standard OTP behaviours, (gen_server, etc) most of the time you don't need to use the global module directly.

error:spawn a process with only argument which is a recursive function that calls io:format

I use EUNIT module and including "eunit/include/eunit.hrl". I call spawn/1 with the argument func/0 to spawn a new process in a test function and call io:format/1 in the new process. The argument func/0 is a recursive function like this:
func() ->
A = 2,
io:format("#######~p~n", [A]),
timer:sleep(1000),
func().
Then
10> bt:test().
All 2 tests passed.
ok
11>
=ERROR REPORT==== 19-Jun-2013::19:50:54 ===
Error in process <0.122.0> with exit value: {terminated,[{io,format,[<0.121.0>,"
#######~p~n",[2]],[]},{bt,func,0,[{file,"bt.erl"},{line,6}]}]}
What's wrong and what should I do?
If I correcly understand the problem is that you are spawning a process running a never ending function func(), but when the EUnit process terminates it probably closes standard output.
This makes the process issuing io:format() to exit (raises an exception). Indeed the ERROR REPORT mentions exactly this function.
My suggestion is to review the need of spawning a function that never ends.
The way fun() is written, it's infinite recursive. It's basically:
fun() ->
fun().
That will never return (keep running) and is probably the reason for termination by EUNIT.

Which one should I use exit, error or throw?

Could you tell me when to use throw, exit and error?
1> catch throw ({aaa}).
{aaa}
2> catch exit ({aaa}).
{'EXIT',{aaa}}
3> catch gen_server:call(aaa,{aaa}).
{'EXIT',{noproc,{gen_server,call,[aaa,{aaa}]}}}
4> catch exit("jaj")
{'EXIT',"jaj"}
There are 3 classes which can be caught with a try ... catch: throw, error and exit.
throw is generated using throw/1 and is intended to be used for non-local returns and does not generate an error unless it is not caught (when you get a nocatch error).
error is generated when the system detects an error. You can explicitly generate an error using error/1. The system also includes a stacktrace in the generated error value, for example {badarg,[...]}.
exit is generated using exit/1 and is intended to signal that this process is to die.
The difference between error/1 and exit/1 is not that great, it more about intention which the stacktrace generated by errors enhances.
The difference between them is actually more noticeable when doing catch ...: when throw/1 is used then the catch just returns the thrown value, as is expected from a non-local return; when an error/1 is used then the catch returns {'EXIT',Reason} where Reason contains the stacktrace; while from exit/1 catch also returns {'EXIT',Reason} but Reason only contains the actual exit reason. try ... catch looks like it equates them, but they are/were very different.
[UPDATED]
I glossed over the important difference between throw and error, pointed out by Robert Virding. This edit is just for the record!
throw error is to be used where one would use throw in other languages. An error in a running process has been detected by your code, which signals an exception with error/1. The same process catches it (possibly higher up in the stack), and the error is to be handled within the same process. error always brings with it a stacktrace.
throw is to be used not to signal an error, but just to return a value from a deeply nested function.
Since it unwinds the stack, calling throw returns the thrown value to the place it was caught. As in the case of error, we're catching stuff that was thrown, only what was thrown wasn't an error but rather just a value passed up the stack. This is why throw does not bring with it a stacktrace.
As a contrived example, if we wanted to implement an exists function for lists, (similar to what list:any does) and as an exercise without doing the recursing ourselves, and using just list:foreach, then throw could be used here:
exists(P, List) ->
F = fun(X) ->
case P(X) of
true -> throw(true);
Whatever -> Whatever
end
end,
try lists:foreach(F, List) of
ok -> false
catch
true -> true
end.
A value thrown but not caught is treated as an error: a nocatch exception will be generated.
EXIT is to be signaled by a process when it 'gives up'. The parent process handles the EXIT, while the child process just dies. This is the Erlang let-it-crash philosophy.
So exit/1's EXIT is not to be caught within the same process, but left to the parent. error/1's errors are local to the process - i.e., a matter of what happens and how it is handled by the process itself; throw/1 is used for control flow across the stack.
[UPDATE]
This tutorial explains it well: http://learnyousomeerlang.com/errors-and-exceptions
Note there is also a exit/2 - called with a Pid of a process to send the EXIT to.
exit/1 implies the parent process.
I'm new to Erlang, but here's how I think about what these things are, their differences, what they're used for, etc.:
throw: a condition that should be handled locally (i.e. within the current process). E.g. caller is looking for an element in a collection, but does not know if the collection actually contains such an element; then, the callee could throw if such an element is not present, and the caller detect absence by using try[/of]/catch. If caller neglects to do this, then this gets turned into an nocatch error (explained below).
exit: The current process is done. E.g. it has simply finished (in that case, you'd pass normal, which is treated the the same as the original function returning), or its operation was cancelled (E.g. it normally loops indefinitely but has just received a shut_down message).
error: the process has done something and/or reached a state that the programmer did not take into account (E.g. 1/0), believes is impossible (E.g. case ... of encounters a value that does not match any case), or some precondition is not met (E.g. input is nonempty). In this case, local recovery doesn't make sense. Therefore, neither throw nor exit is appropriate. Since this is unexpected, a stack trace is part of the Reason.
As you can see, the above list is in escalating order:
throw is for sane conditions that the caller is expected to handle. I.e. handling occurs within the current process.
exit is also sane, but should end the current process simply because the process is done.
error is insane. Something happened that can't reasonably be recovered from (usually a bug?), and local recovery would not be appropriate.
vs. other languages:
throw is analogous to the way checked exceptions are used in Java. Whereas, error is used in a manner more analogous to unchecked exceptions. Checked exceptions are exceptions you want the caller to handle. Java requires you to either wrap calls in try/catch or declare that your method throws such exceptions. Whereas, unchecked exceptions generally propagate to the outermost caller.
exit does not have a good analog in more "conventional" languages like Java, C++, Python, JavaScript, Ruby, etc. exit vaguely like an uber-return: instead of returning at the end, you can return from the middle of a function, except you don't just return from the current function, you return from them ALL.
exit Example
serve_good_times() ->
receive
{top_of_the_mornin, Sender} ->
Sender ! and_the_rest_of_the_day_to_yourself;
{you_suck, Sender} ->
Sender ! take_a_chill_pill;
% More cases...
shut_down ->
exit(normal)
end,
serve_good_times()
end
Since serve_good_times calls itself after almost all messages, the programmer has decided that we don't want to repeat that call in every receive case. Therefore, she has put that call after the receive. But then, what if serve_good_times decides to stop calling itself? This is where exit comes to the rescue. Passing normal to exit causes the process to terminate just as though the last function call has returned.
As such, it's generally inappropriate to call exit in a general purpose library, like lists. It's none of the library's business whether the process should end; that should be decided by application code.
What About Abnormal exit?
This matters if another process (the "remote" process) is linked to the "local" process that calls exit (and process_flag(trap_exit, true) was not called): Just like the last function returning, exit(normal) does not cause remote process to exit. But if the local process makes a exit(herp_derp) call, then the remote process also exits with Reason=herp_derp. Of course, if the remote process is linked to yet more processes, they also get exit signal with Reason=herp_derp. Therefore, non-normal exits result in a chain reaction.
Let's take a look at this in action:
1> self().
<0.32.0>
2> spawn_link(fun() -> exit(normal) end).
<0.35.0>
3> self().
<0.32.0>
4>
4>
4> spawn_link(fun() -> exit(abnormal) end).
** exception exit: abnormal
5> self().
<0.39.0>
6>
The first process that we spawned did not cause the shell to exit (we can tell, because self returned the same pid before and after spawn_link). BUT the second process did cause the shell to exit (and the system replaced the shell process with a new one).
Of course, if the remote process uses process_flag(trap_exit, true) then it just gets a message, regardless of whether the local process passes normal or something else to exit. Setting this flag stops the chain reaction.
6> process_flag(trap_exit, true).
false
7> spawn_link(fun() -> exit(normal) end).
<0.43.0>
8> self().
<0.39.0>
9> flush().
Shell got {'EXIT',<0.43.0>,normal}
ok
10>
10>
10> spawn_link(fun() -> exit(abnormal) end).
<0.47.0>
11> self().
<0.39.0>
12> flush().
Shell got {'EXIT',<0.47.0>,abnormal}
Recall that I said that exit(normal) is treated like the original function returning:
13> spawn_link(fun() -> ok end).
<0.51.0>
14> flush().
Shell got {'EXIT',<0.51.0>,normal}
ok
15> self().
<0.39.0>
What do you know: the same thing happened as when exit(normal) was called. Wonderful!

Erlang error when spawning a process

I start a process as follows
start() ->
register (dist_erlang, spawn(?MODULE, loop, [])),
ok.
But get the following error when trying to run start().
Error in process <0.62.0> with exit value: {undef,[{dist_erlang,loop,[]}]}
The module is called dist_erlang.
What am I doing wrong?
Thanks
Although the question is old, I post what helped me when I was wrestling with the Erlang compiler.
This (incomplete) snippet
-export([start/0]).
start() ->
Ping = spawn(?MODULE, ping, [[]]),
...
ping(State) ->
receive
...
end.
fails with error:
=ERROR REPORT==== 2-Sep-2013::12:17:46 ===
Error in process <0.166.0> with exit value: {undef,[{pingpong,ping,[[]],[]}]}
until you export explicitly ping/1 function. So with this export:
-export([start/0, ping/1]).
it works. I think that the confusion came from some examples from Learn You Some Erlang for great good where the modules sometimes have
-compile(export_all).
which is easy to overlook
Based on your previous question, your loop function takes one parameter, not none. Erlang is looking for loop/0 but can't find it because your function is loop/1.
The third parameter to spawn/3 is a list of parameters to pass to your function, and in the case you've shown the list is empty. Try:
register (dist_erlang, spawn(?MODULE, loop, [[]]))
In this case, the third parameter is a list that contains one element (an empty list).

Resources