Debugging
When debugging, it is often helpful to output the value of an expression or variable.
We might try something like:
def sum(x: Int32, y: Int32): Int32 =
println(x);
println(y);
x + y
Unfortunately this does not work:
❌ -- Type Error -------------------------------------------------- Main.flix
>> Impure function declared as pure.
1 | def sum(x: Int32, y: Int32): Int32 =
^^^
impure function.
The problem is that printing is inherently an effectful operation and hence we
cannot use it to debug our pure functions! We could make our sum
function have
the IO
effect, but that is rarely what we want. Fortunately, Flix has a
built-in debugging facility that allows us to do print-line debugging.
The dbg Function
Flix has a dbg
(short for "debug") function, with the same signature as the identity
function:
def dbg(x: a): a
The dbg
"function" isn't really a function; rather its internal compiler
magic that allows you to print any value while fooling the type and effect
system into believing that it is still pure. Using the dbg
function this
program:
def sum(x: Int32, y: Int32): Int32 =
dbg(x);
dbg(y);
x + y
Now compiles and runs.
The dbg
function returns its argument. Hence its convenient to use in many
situations.
For example, we can write:
def sum(x: Int32, y: Int32): Int32 = dbg(x + y)
to print the value of x + y
and return it.
We can also use it inside e.g. a for-yield
expression:
for(i <- List.range(0, 10);
j <- dbg(List.range(i, 10)))
yield (i, j)
Or in a pipeline:
List.range(1, 100) |>
List.map(x -> dbg(x + 1)) |>
List.filter(x -> dbg(x > 5))
Debug Format
The dbg
expression (and its variants) do not use the ToString
trait.
Instead they print the internal Flix representation of the given value.
For example, the expression:
dbg(1 :: 2 :: Nil)
prints:
Cons(1, Cons(2, Nil))
We can also print values that do not have a ToString
instance:
dbg(x -> x + 123)
prints:
Int32 -> Int32
We can always obtain the ToString
representation by using an interpolated
string. For example:
dbg("${x}")
Debug Variants
The dbg
function comes in three variants:
dbg
: Prints its argument.dbg!
: Prints its argument and source location.dbg!!
: Prints its argument, source location, and source code.
The following program:
def main(): Unit =
dbg("A message");
dbg!("Another message");
dbg!!("A third message");
()
prints:
"A message"
[C:\tmp\flix\Main.flix:3] "Another message"
[C:\tmp\flix\Main.flix:4] A third message = "A third message"
The third dbg!!
variant is intended to be used in situations like:
let x = 123;
let y = 456;
dbg!!(x + y)
where it prints:
[C:\tmp\flix\Main.flix:3] x + y = 579
Note: The
dbg
expression should not be used in production code.
Warning: The Flix compiler treats the
dbg
expression as pure, hence under certain circumstances the compiler may reorder or entirely remove a use ofdbg
.