The Dumbest Server

To showcase my problem, let me show you the dumbest possible way to duplicate a number in Erlang while also showing you the simplest possible version of a gen_server implementation:

So, when we want to duplicate a number, we start a new gen_server, we keep the result on its state and then we use sys:get_state/1 to retrieve it.

Let’s try it on a console:

1> c(dumb_math).

{ok,dumb_math}

2> dumb_math:dup(1).

2

The Unexpected Exception

So far, so good. Now, according to the doc we read before, if init/1 function fails, gen_server:start_link/3 should return {error, Reason} and therefore we can expect line #5 in our code to produce a badmatch exception. But instead of that, look what happens…

3> dumb_math:dup(bad).

** exception exit: badarith

in function dumb_math:init/1 (dumb_math.erl, line 8)

in call from gen_server:init_it/6 (gen_server.erl, line 328)

in call from proc_lib:init_p_do_apply/3 (proc_lib.erl, line 240)

Ok, that’s odd, but in any case we can actually use the second, maybe cleaner option that the docs offer. That is to return {stop, Reason} instead of just failing. And we can also do something with gen_server:start_link’s return value instead of just letting the pattern-matching crash. Something like this:

This time we added a function clause to our init/1 function that returns {stop, notnum} if the input is not a number and therefore can’t be multiplied by 2. We also dealt with that situation on dup/1 by handling the {error, Reason} result described by the docs above.

Let’s see how that goes…

1> c(dumb_math).

{ok,dumb_math}

2> dumb_math:dup(1).

2

3> dumb_math:dup(bad).

** exception exit: notnum

4>

Ok, notnum is there, but it’s still an exception, you see? I was expecting notnum to be the result of that function.

Catch me if you can!!

In any case, we know how to deal with exceptions, don’t we? Let’s see…

3> dumb_math:dup(bad).

** exception exit: notnum

4> catch dumb_math:dup(bad).

** exception exit: notnum

5> try dumb_math:dup(bad) catch Type:Error -> {Type, Error} end.

** exception exit: notnum

As you can see, there is simply no way to catch that exception.