Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Erlang "badarg", Not sure how to handle

Tags:

erlang

Before I start, I have already checked out Handle badarg in Erlang But I am still not successful in my undefined checks so I removed them.

I am building a dummy bank process and when a client does a balance query check to the bank process, the program exits, saying:

Error in process <0.373.0> with exit value:
{badarg,[{project4,client,3,
                   [{file,"/Users/owner/Desktop/bank.erl"},
                    {line,27}]}]}

=ERROR REPORT==== 26-Oct-2016::13:34:57 ===
Error in process <0.379.0> with exit value:
{badarg,[{project4,client,3,
                   [{file,"/Users/owner/Desktop/bank.erl"},
                    {line,27}]}]}

=ERROR REPORT==== 26-Oct-2016::13:34:57 ===
Error in process <0.375.0> with exit value:
{badarg,[{project4,client,3,
                   [{file,"/Users/owner/Desktop/bank.erl"},
                    {line,27}]}]}

=ERROR REPORT==== 26-Oct-2016::13:34:58 ===
Error in process <0.377.0> with exit value:
{badarg,[{project4,client,3,
                   [{file,"/Users/owner/Desktop/bank.erl"},
                    {line,27}]}]}
<0.378.0> Balance request: 54> 
=ERROR REPORT==== 26-Oct-2016::13:34:58 ===
Error in process <0.378.0> with exit value:
{badarg,[{project4,client,3,
                   [{file,"/Users/owner/Desktop/bank.erl"},
                    {line,39}]}]}
<0.372.0> Balance request: 54> 
=ERROR REPORT==== 26-Oct-2016::13:34:58 ===
Error in process <0.372.0> with exit value:
{badarg,[{project4,client,3,
                   [{file,"/Users/owner/Desktop/bank.erl"},
                    {line,39}]}]}

The code for the simulation is here:

-module(bankSim).
-export([start/0, negativeOrPositive/0, sleep/1, generate_rand_int_list/3, generate_rand/2, client/3, clientSpawn/2, bank/2]).

negativeOrPositive() -> 
    M = rand:uniform(),
    if
        M =< 0.5 -> 
            1;
        true -> 
            -1
    end.

sleep(T) ->
    receive
        after T -> ok
    end.

generate_rand_int_list(N,StartVal,Lim) ->
    lists:map(fun (_) -> (rand:uniform(Lim-StartVal) + StartVal)* negativeOrPositive() end, lists:seq(1,N)).

generate_rand(StartVal, Lim) ->
    rand:uniform(Lim-StartVal) + StartVal.

client([], _ , BankID) ->
    BankID ! {goodbye};
client([H|T], Count, BankID) ->
    BankID ! {transaction, self(), H},
    receive
        {Amount, Balance, Success} ->
            io:format("Client: ~w, Amount requested: ~w, Bank Balance: ~w, Transaction successful ~w ~n",[self(), Amount, Balance, Success]);
        { X } ->
            io:format("The balance is ~w ~n", [X])
    end,    
    sleep(generate_rand(500, 1500)),
    Mod = Count rem 5,
    if 
        Mod == 0 -> 
            io:format("~w Balance request: ",[ self() ]),
            BankID! {balance, self()};
        true -> 
            ok
    end,
    client(T, Count + 1, BankID).

clientSpawn(0, _) ->
        io:format("Finished spawning clients ~n",[]);
clientSpawn(N, BankID) -> 
        spawn(bankSim, client, [ generate_rand_int_list( generate_rand(10, 20), 0, 100) , 1, BankID] ),
        clientSpawn(N-1, BankID).


bank(Balance, 0) ->
    io:format("Banking simulation ended with a final balance of ~w ~n", [Balance]),
    io:format("simulation completed ~n", []);
bank(Balance, NumClients) ->
    receive
        {balance, Client} ->
            Client ! {Balance};
        {transaction, Client, Amount} ->
            NewBalance = Balance + Amount,
            if 
                NewBalance =< 0 ->
                    Client ! {Amount, NewBalance, no},
                    bank(Balance, NumClients);
                NewBalance > 0 ->
                    Client ! {Amount, NewBalance, yes},
                    bank(NewBalance, NumClients);
                true -> 
                    io:format("This will never be printed")
            end;
        goodbye ->
            NewNumClients = NumClients - 1,
            bank(Balance, NewNumClients)
    end.


start()->
    N = generate_rand(2,10),
    register(bank ,spawn(bankSim, bank, [generate_rand(2000,3000), N])),
    clientSpawn(N,bank).

Any help would be appreciated.

like image 894
Q.H. Avatar asked Oct 26 '16 17:10

Q.H.


1 Answers

The Erlang documentation will tell you that badarg means "The argument is of wrong data type, or is otherwise badly formed." Which I never find very elucidating.

Dogbert points out that you missed a recursive call to bank/2 in one of your cases. This is the source of your badargs -- but why?

I always think of badarg as meaning "bad argument sent to a BIF". If you're calling a regular Erlang function, you'll get a function_clause error, meaning that there was no function clause that matched your data.

The error message you're getting lists two different line numbers. One is for the line

BankID ! {transaction, self(), H},

and the other for

BankID! {balance, self()};

The argument that is bad is BankID. The reason that it's bad is because it is an atom, bank. In your start/0 function, you spawn a new bank process and then register the PID of that process as bank. Then in your client, you're sending messages to the bank atom and having Erlang resolve that to the registered PID.

It works for a while, but when you hit the missing-recusion case your bank process terminates. Now there's nobody registered behind the bank atom, and the send operator blows up because it can't send to a defunct name.

If you changed you code to

Bank = spawn(bankSim, bank, [generate_rand(2000,3000), N]),
clientSpawn(N, Bank).

then you would not get the badarg, because it's not an error to send messages to a PID where nobody's running. You might enjoy trying that without fixing the bank loop and seeing what happens.

like image 67
Nathaniel Waisbrot Avatar answered Sep 28 '22 00:09

Nathaniel Waisbrot