Debugging Essentials
In this introductory guide, we’re only scratching the surface of debugging in Elixir, but I’d like to introduce three vital tools that will be beneficial while exploring the code examples in this book.
dbg/2
Elixir version 1.18 includes the powerful debugging tool dbg/2. It not only prints the passed value, returning
it simultaneously, but also outlines the code and location. Here’s an example:
iex(1)> name = "Elixir"
"Elixir"
iex(2)> dbg(name)
[iex:2: (file)]
name #=> "Elixir"
"Elixir"
iex(3)> dbg(IO.puts("Hello World!"))
Hello World!
[iex:3: (file)]
IO.puts("Hello World!") #=> :ok
:ok
Beginners often find it odd that dbg/2 and IO.inspect/2 return the
value they print. This becomes useful later, once you chain functions together
with the pipe operator (|>), because
the printed value stays in the chain and the code keeps flowing.
|
The /2 after dbg is the function’s arity, the number of arguments it
takes. So dbg/2 is a function that accepts two arguments, even though our
example only passes one. That works because the second argument has a default
value, so it is optional. We cover arity
and default arguments in later chapters.
|
IO.inspect/2
The function IO.inspect(item, opts \\ []) is a staple in Elixir debugging.
Although it’s less feature-rich than dbg/2, its usage remains widespread,
given its history and straightforward application. You can inject IO.inspect/2
into your code at any point, printing the value of an expression to your console
- perfect for verifying a variable’s value or a function call’s result.
For example:
iex> name = "Elixir"
"Elixir"
iex> IO.inspect(name)
"Elixir"
"Elixir"
Feel free to always use dbg/2 instead of IO.inspect/2.
However, if you’re working with older codebases, you’ll likely
encounter IO.inspect/2.
|
i/1
Finally, the IEx helper function i/1 offers useful insights about any data
type or structure. Launch an IEx session with iex in your terminal, and then
call i() with any term to obtain information about it.
Here’s an example:
iex> name = "Elixir"
"Elixir"
iex> i(name)
Term
"Elixir"
Data type
BitString
Byte size
6
Description
This is a string: a UTF-8 encoded binary. It's printed surrounded by
"double quotes" because all UTF-8 encoded code points in it are printable.
Raw representation
<<69, 108, 105, 120, 105, 114>>
Reference modules
String, :binary
Implemented protocols
Collectable, IEx.Info, Inspect, JSON.Encoder, List.Chars, String.Chars
This output tells us that "Elixir" is a 6-byte BitString and gives
further details like the string’s raw representation and the protocols
it implements.