%% Used destructive assignment in the process dictionary 
%% to keep count of handled exceptions.
%%
%% Usage: start from command line with
%%     erlc exceptions.erl
%%     erl -noinput -s exceptions main 200000

-module(except). 
-export([main/1]). 


blowup(N) when N rem 2 == 0 -> throw({lo_exception, N});
blowup(N) -> throw({hi_exception, N}).


lo_fun(N) ->
    case catch blowup(N) of
        {lo_exception, N1} -> put(lo_count, get(lo_count) + 1);
        {hi_exception, N2} -> throw({hi_exception, N2})
    end.


hi_fun(N) -> 
    case catch lo_fun(N) of
        {hi_exception, N1} -> put(hi_count, get(hi_count) + 1);
        _ -> true
    end.


some_fun(N) when N > 0 ->
    case catch hi_fun(N) of
        {lo_exception, N1} -> io:fwrite("~s~n", ["lo_exception should not get here."]);
        {hi_exception, N2} -> io:fwrite("~s~n", ["hi_exception should not get here."]);
        _ -> true
    end,
    some_fun(N - 1);
some_fun(0) -> true.


main([Arg]) ->
    Num = list_to_integer(atom_to_list(Arg)),
    put(hi_count, 0),
    put(lo_count, 0),
    some_fun(Num),
    io:fwrite("~s~w ~s~w~n", ["Exceptions: HI=", get(hi_count),"/ LO=", get(lo_count)]),
    halt(0).