Search code examples
erlangswitch-statementmessage-passing

Erlang: case..of construct for function call return?


The errors generated by the code are

2> X = "2".
"2"
3> case_:main(X).
main 50
sender 50
** exception error: bad argument
     in function  case_:sender/1 (case_.erl, line 14)
     in call from case_:main/1 (case_.erl, line 6)
4> Z = 2.
2
5> case_:main(Z).
** exception error: bad argument
     in function  io:format/3
        called as io:format(<0.25.0>,"main ~p~n",2)
     in call from case_:main/1 (case_.erl, line 5)
6> 

On the first try I tried to pass an string which made it a lot farther than the second try passing an integer. I'm not sure why this doesn't work.

The function call sender(Input) should return {Data} from the receiver() function call.

I definitely need the message passing part of the program since I'm trying to write a loop that takes messages, evaluates them and returns the result; but maybe the case...of statement could be thrown out.

-module(case_).
-export([main/1, sender/1, receiver/0]).

main(Input) ->
    io:format("main ~p~n",Input),
    case sender(Input) of
        {Data} ->
            io:format("Received ~p~n",Data)
    end.

sender(Input) ->
    io:format("sender ~p~n",Input),
    Ref = make_ref(),
    ?MODULE  ! { self(), Ref, {send_data, Input}},
    receive
        {Ref, ok, Data} ->
            {Data}      
    end.    

receiver() ->
    io:format("receiver ~n"),
    receive
        {Pid, Ref, {send_data, Input}} ->
            Pid ! { Ref, ok, Input + Input} 
    end.

Solution

  • Happily, badarg fix is easily done. io:format/2 takes a list of terms as its the second argument. See:

    (Erlang R15B02 (erts-5.9.2) [source] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]
    
    Eshell V5.9.2  (abort with ^G)
    1> io:format("main ~p~n", 2).
    ** exception error: bad argument
         in function  io:format/3
            called as io:format(<0.24.0>,"main ~p~n",2)
    2> io:format("main ~p~n", [2]).
    main 2
    ok
    

    Your second problem is that ?MODULE just returns an atom of the current module's name. You'll want to send your message to a process. If you modify your code to look like so:

    -module(case_).
    -export([main/1, sender/2, receiver/0]).
    
    main(Input) ->
        io:format("main ~p~n", [Input]),
        Recv = spawn(?MODULE, receiver, []),
        case sender(Recv, Input) of
            {Data} ->
                io:format("Received ~p~n", [Data])
        end.
    
    sender(Pid, Input) ->
        io:format("sender ~p~n", [Input]),
        Ref = make_ref(),
        Pid ! { self(), Ref, {send_data, Input}},
        receive
            {Ref, ok, Data} ->
                {Data}
        end.
    
    receiver() ->
        io:format("receiver ~n"),
        receive
            {Pid, Ref, {send_data, Input}} ->
                Pid ! { Ref, ok, Input + Input}
        end.
    

    Then the interaction in the repl:

    Erlang R15B02 (erts-5.9.2) [source] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]
    
    Eshell V5.9.2  (abort with ^G)
    1> c("case_").
    {ok,case_}
    2> case_:main(2).
    main 2
    sender 2
    receiver 
    Received 4
    ok