[erlang-questions] wierd "function not used" problem - code included

0 views
Skip to first unread message

deepblue_other

unread,
Oct 5, 2008, 12:39:41 PM10/5/08
to erlang-q...@erlang.org

Hello, its me again...
so I've been having this problem for days, with the bellow code. Most of it
is straight out of the "Programming Erlang" book from Joe Armstrong...
however when Im compiling it its telling me that the function data_process/1
is not being used, gives me a warning, but then still compiles. however when
Im sending data from a client side via TCP ofcourse it exits on me because
there's nothing to process the message...

I HAVE NO IDEA WHAT'S WRONG WITH IT.
I've read up on all the spawn_link() definitions and as far as I can tell Im
using it correctly... the PiD that spawn_link() returns is being returned so
it executes successfully.
please help out, its stalling my project progress.
thanks


-module(tcp_manager).
%API--------------------------------------------
-export([start/1]).
%-----------------------------------------------
start(Port) ->
{ok, ListeningSocket} =
gen_tcp:listen( Port, [ binary, %receive data in binary form
{packet , 0},
{reuseaddr, true},
%hybrid - active for only one message
%it auto-receives one message after
which it blocks
%has to be set to active-once again to
receive the next message
{active , once} ] ),
accept_connection(ListeningSocket).
%-----------------------------------------------
accept_connection(ListeningSocket) ->

io:format("waiting to accept~n"),
{ok, Socket} = gen_tcp:accept(ListeningSocket),
io:format("Socket is:~p~n", [Socket]),

%-----------------------------------------------
Listen_for_errors =
fun() ->
io:format("listening started~n"),
receive
{'EXIT', Pid, Why} ->
io:format("~p exited because:~p", [Pid,Why]);
Other ->
io:format("Other:~p~n", [Other])
end
end,
Listen_for_errors(),
%-----------------------------------------------

Handler_process = spawn_link(?MODULE, data_process, [Socket]), %,[]]),
io:format("handlers process ID:~p", [Handler_process]).

accept_connection(ListeningSocket).
%-----------------------------------------------
data_process( Socket, DataSoFar) ->
io:format("responder_loop() entered~n"),

receive
{tcp, Socket, Data} ->
%Source_ip = inet:peername(Socket),
%io:format("*~p - data coming in:~p~n",[Source_ip,Data]),
io:format("works - Data:~p~n", [Data]),
%has to be done, since its an active-once socket
inet:setopts( Socket, [{active,once}] ),
data_process( Socket,
%append the new binary fragment to what has
been received so far
[Data | DataSoFar] );

{tcp_closed, Socket} ->
io:format("*client socket closed~n");
%reverse because data has been appended to the head of the list
as it was coming in
list_to_binary(lists:reverse(SoFar));
Other ->
io:format("undefined message came in:~p", [Other])
end.
%-----------------------------------------------
--
View this message in context: http://www.nabble.com/wierd-%22function-not-used%22-problem---code-included-tp19826465p19826465.html
Sent from the Erlang Questions mailing list archive at Nabble.com.

_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions

Edwin Fine

unread,
Oct 5, 2008, 4:02:02 PM10/5/08
to erlang-q...@erlang.org

Well, there are a couple of problems, but the reason why you get that warning
is that you have to export a function that you spawn_link to using
Module/Func/Args syntax, otherwise you would have to

Handler_process = spawn_link(fun() -> data_process(Socket, []) end),

The other problem is that your fun Listen_for_errors may as well be inline,
i.e. you could change this code:

%-----------------------------------------------
Listen_for_errors =
fun() ->
io:format("listening started~n"),
receive
{'EXIT', Pid, Why} ->
io:format("~p exited because:~p", [Pid,Why]);
Other ->
io:format("Other:~p~n", [Other])
end
end,
Listen_for_errors(),
%-----------------------------------------------

Handler_process = spawn_link(?MODULE, data_process, [Socket, []]),

To this:

%-----------------------------------------------


io:format("listening started~n"),
receive
{'EXIT', Pid, Why} ->
io:format("~p exited because:~p", [Pid,Why]);
Other ->
io:format("Other:~p~n", [Other])

end,
%-----------------------------------------------

Handler_process = spawn_link(?MODULE, data_process, [Socket, []]),


--
View this message in context: http://www.nabble.com/wierd-%22function-not-used%22-problem---code-included-tp19826465p19828568.html

deepblue_other

unread,
Oct 5, 2008, 6:55:10 PM10/5/08
to erlang-q...@erlang.org

beautiful, it works now.
Thank you Edwin.
so when I want to use spawn_link() with a named function that function has
to be exported?
same stands for regular spawn()?

just a side question:
once a certain "receive" configuration is set for a process it can never be
changed to another "receive" configuration? it just popped in my head here
when you said that i can inline the error "receive".

thanks for your time

--
View this message in context: http://www.nabble.com/wierd-%22function-not-used%22-problem---code-included-tp19826465p19829936.html

Edwin Fine

unread,
Oct 5, 2008, 2:25:47 PM10/5/08
to erlang-q...@erlang.org

Your code as pasted here does not compile, even after correcting the
spawn_link arity. There are syntax errors. Please post a version that
compiles.
--
View this message in context: http://www.nabble.com/wierd-%22function-not-used%22-problem---code-included-tp19826465p19827568.html

Edwin Fine

unread,
Oct 5, 2008, 9:06:22 PM10/5/08
to erlang-q...@erlang.org

deepblue_other wrote:
>
> so when I want to use spawn_link() with a named function that function has
> to be exported?
> same stands for regular spawn()?
>

Yes, if you use a spawn that takes Module, Function, Args, like spawn/3,
spawn/4, spawn_link/3, spawn_link/4,.... Or apply/3. And so on.

In general if you provide a so-called "MFA" (Module, Func, Args) to a
function, the Func has to be exported from Module, even if the Func is only
for internal use within Module.

It's important to know that the shell is your friend. It's critical to try
out little pieces of code in the shell to see if they work the way you
expect. For example, if you wanted to see if spawn could see your
data_process function, you could have tried it in the shell (I'm passing the
atom 'junk' instead of a real socket because I know the call will fail
because it's not exported, so the socket is not needed):

1> c(tcp_manager).
./tcp_manager.erl:33: Warning: function data_process/2 is unused
{ok,tcp_manager}
2> spawn(tcp_manager, data_process, [junk, []]).
<0.40.0>
3>
=ERROR REPORT==== 5-Oct-2008::20:49:23 ===
Error in process <0.40.0> with exit value:
{undef,[{tcp_manager,data_process,[junk,[]]}]}

deepblue_other wrote:
>
> just a side question:
> once a certain "receive" configuration is set for a process it can never
> be changed to another "receive" configuration? it just popped in my head
> here when you said that i can inline the error "receive".
>

I perhaps did not make myself clear. What I meant by saying you could inline
it is that I didn't see the value of writing

Fun = fun() -> do_something(), do_something_else() end,
Fun().

That's the same as writing

do_something(),
do_something_else()

It is better in this case to put the code into a separate function. Better,
because you can hot-swap the code and change that function.

There's an excellent article about hot code swapping
http://http://spawnlink.com/articles/rules-of-hot-code-swapping/ here .


> %-----------------------------------------------
> Listen_for_errors =
> fun() ->
> io:format("listening started~n"),
> receive
> {'EXIT', Pid, Why} ->
> io:format("~p exited because:~p", [Pid,Why]);
> Other ->
> io:format("Other:~p~n", [Other])
> end
> end,
> Listen_for_errors(),
> %-----------------------------------------------
>

Finally, I'm not sure what Listen_for_errors() is supposed to do. It's just
going to sit there forever in the receive, waiting for the first message
that is sent (or en exit signal), and print it out (thus throwing it away),
and return. What did you want it to do?
--
View this message in context: http://www.nabble.com/wierd-%22function-not-used%22-problem---code-included-tp19826465p19830744.html

deepblue_other

unread,
Oct 6, 2008, 11:21:56 AM10/6/08
to erlang-q...@erlang.org

no I understood what you wanted to say, I just had a case in my mind where
for example a "receive configuration" is active for a process, and a message
that matches comes in, and the clause starts executing its expressions and
one of the expressions calls another function that within it contains
another "receive configuration" - the new configuration would now be active,
and the old one would stop?

also the expressions listed bellow a "receive configuration" are executed
even though the "receive" essentially blocks the process in waiting state?

as you can tell Im slightly confused as to how the "receive" affects the
present/future activity of a process


Edwin Fine wrote:
>
> It is better in this case to put the code into a separate function.
> Better, because you can hot-swap the code and change that function.
>
> There's an excellent article about hot code swapping
> http://http://spawnlink.com/articles/rules-of-hot-code-swapping/ here .
>

I will read this through now

Edwin Fine wrote:
>
>
>
>> %-----------------------------------------------
>> Listen_for_errors =
>> fun() ->
>> io:format("listening started~n"),
>> receive
>> {'EXIT', Pid, Why} ->
>> io:format("~p exited because:~p", [Pid,Why]);
>> Other ->
>> io:format("Other:~p~n", [Other])
>> end
>> end,
>> Listen_for_errors(),
>> %-----------------------------------------------
>>
> Finally, I'm not sure what Listen_for_errors() is supposed to do. It's
> just going to sit there forever in the receive, waiting for the first
> message that is sent (or en exit signal), and print it out (thus throwing
> it away), and return. What did you want it to do?
>

Listen_for_errors() was meant to catch the errors that were produced because
I didnt export the function I used in spawn_link() :) and just to see if the
data was coming in from the client.

thanks Edwin
--
View this message in context: http://www.nabble.com/wierd-%22function-not-used%22-problem---code-included-tp19826465p19840082.html

deepblue_other

unread,
Oct 5, 2008, 2:34:30 PM10/5/08
to erlang-q...@erlang.org

deepblue_other

unread,
Oct 5, 2008, 12:54:32 PM10/5/08
to erlang-q...@erlang.org

this version that I pasted here is data_process/2 and in spawn_link() Im
using data_process/1, but thats just an error that i made when pasting the
code... Im compiling with:
spawn_link(?MODULE, data_process,[Socket,[]]), so the aritiy is correct

--
View this message in context: http://www.nabble.com/wierd-%22function-not-used%22-problem---code-included-tp19826465p19826635.html

Oscar Hellström

unread,
Oct 5, 2008, 1:39:42 PM10/5/08
to deepblue_other, erlang-q...@erlang.org
Hi,

Calling spawn_link(Module, Function, Args) will call Module:Function(Args) as a fully qualified call. Therefore this Function has to be exported.

Best regards

View this message in context: http://www.nabble.com/wierd-%22function-not-used%22-problem---code-included-tp19826465p19826465.html


Sent from the Erlang Questions mailing list archive at Nabble.com.

_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions

--
Oscar Hellström, os...@erlang-consulting.com
Phone: +44 (0)798 45 44 773
Mobile: +44 (0)207 65 50 337
Web: http://www.erlang-consulting.com

deepblue_other

unread,
Oct 5, 2008, 2:38:14 PM10/5/08
to erlang-q...@erlang.org

here you go, this should compile
sorry about that
thanks

-module(tcp_manager).
%API--------------------------------------------
-export([start/1]).
%-----------------------------------------------
start(Port) ->
{ok, ListeningSocket} =
gen_tcp:listen( Port, [ binary, %receive data in binary form
{packet , 0},
{reuseaddr, true},

{active , once} ] ),
accept_connection(ListeningSocket).
%-----------------------------------------------
accept_connection(ListeningSocket) ->

io:format("waiting to accept~n"),
{ok, Socket} = gen_tcp:accept(ListeningSocket),
io:format("Socket is:~p~n", [Socket]),

%-----------------------------------------------
Listen_for_errors =
fun() ->
io:format("listening started~n"),
receive
{'EXIT', Pid, Why} ->
io:format("~p exited because:~p", [Pid,Why]);
Other ->
io:format("Other:~p~n", [Other])
end
end,
Listen_for_errors(),
%-----------------------------------------------

Handler_process = spawn_link(?MODULE, data_process, [Socket]), %,[]]),
io:format("handlers process ID:~p", [Handler_process]).

%-----------------------------------------------
data_process( Socket, DataSoFar) ->
io:format("responder_loop() entered~n"),

receive
{tcp, Socket, Data} ->

io:format("works - Data:~p~n", [Data]),

inet:setopts( Socket, [{active,once}] ),
data_process( Socket,

[Data | DataSoFar] );

{tcp_closed, Socket} ->
io:format("*client socket closed~n");

Other ->
io:format("undefined message came in:~p", [Other])
end.
%-----------------------------------------------

--
View this message in context: http://www.nabble.com/wierd-%22function-not-used%22-problem---code-included-tp19826465p19827696.html

deepblue_other

unread,
Oct 5, 2008, 2:40:18 PM10/5/08
to erlang-q...@erlang.org

there was a tiny error in the last one, and I put the correct arity in
spawn_link()
this should compile
thanks

Handler_process = spawn_link(?MODULE, data_process, [Socket, []]),

--
View this message in context: http://www.nabble.com/wierd-%22function-not-used%22-problem---code-included-tp19826465p19827720.html

Fredrik Svahn

unread,
Oct 5, 2008, 1:28:51 PM10/5/08
to deepblue_other, erlang-q...@erlang.org
Hi,

The function given as an argument to spawn/spawn_link must be exported.

See e.g. http://erlang.org/doc/getting_started/conc_prog.html#3.1

BR /Fredrik

Robert Virding

unread,
Oct 5, 2008, 2:00:56 PM10/5/08
to deepblue_other, erlang-q...@erlang.org
data_process/1 is never directly called so the warning is correct. However, to be spawn in that way it must be explicitly exported, that is why you get a runtime error. Try exporting data_process/1 or changing the spawn to:

spawn_link(fun () -> data_process(Socket, []) end),

Anyway it should be data_process/2 as there is no data_process/1 defined.

Robert

2008/10/5 deepblue_other <ckt...@gmail.com>
Reply all
Reply to author
Forward
0 new messages