Debugging Erlang code can be tricky at times, especially dealing with badmatch
errors. In general, two good guidelines to keep are:
- Keep functions short
- Use return values directly if you can, instead of binding temporary variables (this will give you the benefit of getting
function_clause
errors etc which are way more informative)
That being said, using the debuggers are usually required to quickly get to the bottom of errors. I recommend to use the command line debugger, dbg
, instead of the graphical one, debugger
(it’s way faster when you know how to use it, and you don’t have to context switch from the Erlang shell to a GUI).
Given the sample expression you provided, the case is often that you have more than just variables being assigned to other variables (which is absolutely unnecessary in Erlang):
run(X, Y) ->
X = something(whatever),
Y = other:thing(more_data),
Debugging a badmatch
error here is aided by using the command line debugger:
1> dbg:tracer(). % Start the CLI debugger
{ok,<0.55.0>}
2> dbg:p(all, c). % Trace all processes, only calls
{ok,[{matched,nonode@nohost,29}]}
3> dbg:tpl(my_module, something, x). % tpl = trace local functions as well
{ok,[{matched,nonode@nohost,1},{saved,x}]}
4> dbg:tp(other, do, x). % tp = trace exported functions
{ok,[{matched,nonode@nohost,1},{saved,x}]}
5> dbg:tp(my_module, run, x). % x means print exceptions
{ok,[{matched,nonode@nohost,1},{saved,x}]} % (and normal return values)
Look for {matched,_,1}
in the return value… if this would have been 0
instead of 1
(or more) that would have meant that no functions matched the pattern. Full documentation for the dbg
module can be found here.
Given that both something/1
and other:do/1
always returns ok, the following could happen:
6> my_module:run(ok, ok).
(<0.72.0>) call my_module:run(ok,ok)
(<0.72.0>) call my_module:something(whatever)
(<0.72.0>) returned from my_module:something/1 -> ok
(<0.72.0>) call other:thing(more_data)
(<0.72.0>) returned from other:thing/1 -> ok
(<0.72.0>) returned from my_module:run/2 -> ok
ok
Here we can see the whole call procedure, and what return values were given. If we call it with something we know will fail:
7> my_module:run(error, error).
** exception error: no match of right hand side value ok
(<0.72.0>) call my_module:run(error,error)
(<0.72.0>) call my_module:something(whatever)
(<0.72.0>) returned from my_module:something/1 -> ok
(<0.72.0>) exception_from {my_module,run,2} {error,{badmatch,ok}}
Here we can see that we got a badmatch
exception, something/1
was called, but never other:do/1
so we can deduce that the badmatch happened before that call.
Getting proficient with the command line debugger will save you a lot of time, whether you debug simple (but tricky!) badmatch
errors or something much more complex.