Dbg_inspect - Debug inspect like in dbg! macro in Rust

Recently I read release notes of Rust 1.32 and was impressed of dbg macro convenience.
Therefore I decided to implement the same concept in Elixir.
Here is the result: GitHub - romul/dbg_inspect: Implementation of dbg! Rust-macro for Elixir

Additional features comparing to IO.inspect/1:

  • Prints representation of expression passed as the first argument
  • Prints filename and line number where Dbg.inspect/2 was called
  • Ability to print values of all variables used in the expression passed as the first argument
  • Colored output
  • Output to :stderr stream
  • No affects prod environment

Output example:

IO.inspect/1 output for the same case:

%{0 => "0", 1 => "1", 2 => "4", 3 => "9"}

14 Likes

Does it return the value it receives like IO.inspect per default?

1 Like

Yes, dbg! macro looks really interesting!

Here’s my take on it: https://github.com/wojtekmach/elixir/commit/27d0019e1d21a3b2f7946a353c2439096df53612.

I think it needs to be in Kernel to be most usable because we need to require/import it to use it, and it’s gonna be annoying to do it every time.

I showed this to a few people and still collecting feedback before proposing this as a feature.

3 Likes

Yes, it does. So you could use it in the middle of pipeline, like this: https://github.com/romul/dbg_inspect/blob/master/test/dbg_test.exs#L71

Well, don’t you mind to unite our efforts to provide even more useful solution than Rust out of the box? As you can see I’ve already implemented several additional features for this macro. I could transfer them to your branch. So we will have 2 commits in the proposal :smile:

2 Likes

I’m pretty happy with the limited feature set I’ve implemented but additional features you’ve added sound interesting too, I’ll definitely play with them. Feel free to argue for these additions when there’s a proposal or send the proposal yourself :slight_smile:

Some feedback:

  • show_vars: true looks interesting. I didn’t have a need for it yet, but will definitely keep it in mind.

    Special casing variables in just the first call seems somewhat arbitrary, it wouldn’t for example show y in Dbg.inspect(x |> max(y)) and that could be a bug or a feature, not sure! Perhaps it should show all variables used in an expression? You can get them using Kernel.binding.

  • if the function is defined as inspect/2, there’s a clash with Kernel.inspect/2 so you wouldn’t be able to import it out of the box. One of my goals for this macro was to be available right away, but perhaps that’s no such a big deal, similarly how writing require IEx; IEx.pry() isn’t? I’ll definitely try this for a few days without this being in Kernel.

  • Dbg is perhaps too similar with OTP’s :dbg module? That being said, I’m not super happy with Kernel.debug name either but couldn’t come up with neither better module nor function name.

2 Likes

Yeah, it was a bug. Fixed already, thank you for pointing it out.
And Kernel.binding looks very promising, I’ll take a look.

Yes, I thought about Dbg.inspect() as an alternative to IO.inspect(), looks similar and almost the same amount of typing. But yeah, looks like Dbg is already used module name. I would be happy with IO.debug(), but it also is not an option :frowning:

hm, why not? I believe it wouldn’t clash with anything. (it could clash with Logger.debug/2, but it’s not common to important that). The only downside of making it IO.inspect IO.debug to me is we’d have to require it.

Yes, that’s because IO module doesn’t have macros yet. And even we put one to it, writing require IO would be necessary. So, there would be not much advantage to put it to Elixir itself.
A standalone library on contrary has a few advantages, for example you could configure coloring or set default options through configuration.

In my implementation I allowed to pass inspect options, e.g.:

debug(foo, inspect: [base: :hex])
debug(foo, inspect: [syntax_colors: [atom: :red]])

but if you want to get the same colour scheme every time, well, it gets tiresome. Some things are configured globally in Elixir (e.g. https://github.com/elixir-lang/elixir/blob/v1.8.0/lib/elixir/lib/calendar.ex#L308:L310) but it’s much less common. So yeah, being able to configure this globally seems more appropriate for a standalone library.

Yep, passing the same configuration as param all the time is too tedious.
There is almost no chance that you would like to use different coloring for the same purpose, but you highly likely could have a preferred color scheme, padding settings and so on.

1 Like