I have some Ruby and Java background and I'm accustomed to having exact numbers of lines in the error logs.
So, if there is an error in the compiled code, I will see the number of line which caused the exception in the console output.
Like in this Ruby example:
my_ruby_code.rb:13:in `/': divided by 0 (ZeroDivisionError)
from my_ruby_code.rb:13
It's simple and fast - I just go to the line number 13 and fix the error.
On the contrary, Erlang just says something like:
** exception error: no match of right hand side value [xxxx]
in function my_module:my_fun/1
in call from my_module:other_fun/2
There are no line numbers to look at.
And if I have two lines like
X = Param1,
Y = Param2,
in 'my_fun', how can understand in which line the problem lies?
Additionally, I have tried to switch to Emacs+Elang-mode from Vim, but the only bonus I've got so far is the ability to cycle through compilation errors inside Emacs (C-k `).
So, the process of writing code and seeking for simple logical errors like 'no match of right hand side' seems to be a bit cumbersome.
I have tried to add a lot of "io:format" lines in the code, but it is additional work which takes time.
I have also tried to use distel, but it requires 10 steps to just open a debugger once.
Questions:
Debugging Erlang code can be tricky at times, especially dealing with badmatch
errors. In general, two good guidelines to keep are:
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.