My tiny but useful trace debugging code... Any suggestions from more experienced D users?

WraithGlade wraithglade at protonmail.com
Thu Jun 26 22:51:06 UTC 2025


A while back (perhaps my first D forum post) I asked about 
implementing an equivalent of other languages' very useful debug 
printing macros such as Julia's `@show` or Nim's `dump` or Rust's 
`dbg!`. Someone on the forum here very helpfully showed me how to 
do it via D's `mixin` feature. I have since then refined my own 
tiny module for doing so, with a few more features. Here is the 
code for it, in my `trace.d` module:

```D
public import std.conv;

/// `trace_prefix` provides the common 
`module_name.function_name-line_number:\t` prefix that is added 
to each of the tracing functions in this module. The other 
functions are likely to be more useful, unless a new function is 
being created that reuses the same trace prefix format.
string trace_prefix(const bool should_mark = false) {
	return `__FUNCTION__ ~ "-" ~ to!string(__LINE__) ~ ` ~ 
(should_mark ? `"*"` : `""`) ~ `~ ": \t"`;
}

/// `trace_message` outputs any arbitrary string you pass it, but 
prefixed by an indicator of what module, function, and line 
number the trace_message is located on, thus aiding print-based 
debugging.
string trace_message(string message) {
	return `writeln(` ~ trace_prefix() ~ ` ~ q"<` ~ message ~ `>");`;
}

/// `show` eases print debugging by printing both an expression 
as a string and its corresponding evaluated value. It is intended 
to be used via `mixin`, such as in `mixin(show("1 + 2")`, which 
will print something like `module.function-line: 1 + 2 == 3`. The 
`module.function-line:` prefix helps distinguish debug printing 
from normal output and also helps to track where output is coming 
from.
///
/// Printing both an expression's code and the expression's value 
makes print debugging easier to keep track of accurately 
(especially when multiple print statements are used, which would 
otherwise be more easily confused with each other) and less 
redundant (since `show` being a macro prevents the user from 
needing to write the expression twice).
///
/// However, assertions (via `assert`) and unit tests (via 
`unittest`) are often a better way to debug and maintain code 
than any form of print debugging, because (1) assertions are 
enforced automatically instead of requiring manual inspection and 
(2) reading through print statements consumes a lot of time in 
aggregate whereas assertions are instantaneous and hence much 
more expedient when well applicable. Nonetheless, print debugging 
is still very useful and intuitive, especially when you don't 
know what a value is at all.
string show(string expr) {
   return `writefln(` ~ trace_prefix() ~ `~ "%s == %s", q"<` ~ 
expr ~ `>", ` ~ expr ~ `);`;
}

/// `trace_scope` returns a mixin string that if mixed in at the 
beginning of a scope inserts code that logs when the current 
scope starts and ends, which may be useful for debugging 
potentially, since it informs of when you are actually inside 
that scope or not, which may or may not be when you think. Use it 
by writing `mixin(trace_scope);`, placing it at the top of the 
scope you intend to trace.
string trace_scope(string scope_name) {
	return
		`writeln(` ~ trace_prefix() ~ ` ~ q"<` ~ scope_name ~ `>" ~ " 
entered");` ~
		`scope(exit) writeln(` ~ trace_prefix(true) ~ ` ~ q"<` ~ 
scope_name ~ `>" ~ " exited");`;
}
```

`show` is for examining the values of things in a clean and 
organized way (the most common use case).

`trace_message` is for any arbitrary string message tagged with 
the module, function, and line.

`trace_scope` is for easier printing of when any specific scope 
starts and ends.

All are useful.

You use them by writing `mixin(trace_function_name(...))` and 
such, since they all return strings and you have to use `mixin` 
to apply arbitrary macros in D. For example, try `mixin(show(1 + 
2))` or `mixin(trace_scope(__FUNCTION__))` or similar.

(Unimportantly, you can see that I'm using snake_case, though 
I've debated on and off using D's camelCase but I've always liked 
snake_case and PascalCase and other conventions more than 
camelCase in languages.)

Anyway, I really like how useful this is and basically this kind 
of print debugging feature should be built in to *all modern 
languages* in my opinion (and indeed is in all of the most 
popular ones in some form and for good reason).

It works fine, but I was wondering what suggestions the D 
community may have regarding both (1) whether or not better 
pre-built functionality for this exists in the D standard library 
and community libraries already and (2) how the above code could 
be improved to be more readable. I tried to use string `format` 
but it didn't even work right when I tried it.

How would *you* refactor it if you were trying to make it more 
polished and readable?

D's string-based `mixin`s that support arbitrary string code are 
useful, but as you can see keeping the quotations delimiters and 
concatenation operations straight above is not very easy and it 
took a long time to get these tracing functions working relative 
to their conceptual simplicity because strings were so subtle and 
easy to confuse oneself with the quote delimiters.

I also figured that other beginners could benefit from the above.

Such tracing functions provide a far better way of print 
debugging than just raw print statements, although assertions and 
unit tests are better in ideal cases because they don't require 
manual examination, but print debugging is useful for when you 
don't know what the state of something actually is at all of 
course.

What are your thoughts, if any?

(PS: Thanks for reading.)


More information about the Digitalmars-d-learn mailing list