Can we compile a list of useful Julia debugging macros and functions?

While learning Julia, I have noticed there are a few useful macros and functions which can be used to inspect functions, decipher which functions or methods are being called, query methods for types, among other similar things.

Here’s a non-exhaustive list of things I have found so far:

  • methods()
  • methodswith()
  • @which
  • @edit / @less

I have found these methods to be extremely useful for figuring out what methods exists, which methods involve certain types, and for more detailed information about the exact code run as part of a method call.

This got me thinking - are there more utilities similar to these, and wouldn’t it be convenient to have a list of them documented somewhere?

There are also macros which are more closely related to compiler debugging or disassembly, rather than Julia language level debugging.

The obvious examples of those are

  • @code_lowered
  • @code_typed
  • @code_llvm
  • @code_native

But these are less likely to be useful on a day-to-day basis as user working at the Julia language level.


@methods(<function>)

List all the methods for a function with name <function>. For example

julia> methods(println)
# 3 methods for generic function "println" from Base:
 [1] println(io::IO)
     @ coreio.jl:5
 [2] println(io::IO, xs...)
     @ strings/io.jl:75
 [3] println(xs...)
     @ coreio.jl:4

@methodswith(<type>)

Similar to the above, however performs a query for all methods which involve the use of type <type>. For example

julia> methodswith(String)
[1] String(s::String) @ Core boot.jl:420
[2] Symbol(s::String) @ Core boot.jl:618
[3] ==(y::PosLenString, x::String) @ WeakRefStrings ~/.julia/packages/WeakRefStrings/31nkb/src/poslenstrings.jl:84
[4] ==(x::String, y::PosLenString) @ WeakRefStrings ~/.julia/packages/WeakRefStrings/31nkb/src/poslenstrings.jl:72
...
# long list follows

@which <target>

Again, similarly to the above, query which method is called for a particular function call. It is easier to understand with an example.

julia> @which parse(Int64, "123")
parse(::Type{T}, s::AbstractString; base) where T<:Integer
     @ Base parse.jl:253

You are probably likely to use this in combination with @edit, see below.

@edit <target> or @less <target>

Launches a text editor at <target>. For example

@edit MyStruct == MyStruct

launches a text editor, at the line where the operator == is defined for this combination of arguments so that the Julia code can be inspected.

Anything else?

I think it would be helpful to have a thread which documents these things. Personally, I often find myself struggling to figure out how to trace down method calls and debug when something doesn’t behave as expected.

When something breaks, as in, does not compile, it is usually relatively easy to figure out from the stack trace where it has gone wrong. On the other hand, these tools are useful when code does compile, but it might not necessarily be obvious to the programmer which methods are being called, etc.

5 Likes

I agree these are helpful, but I want to make sure you know where these live in the official docs. The InteractiveUtils standard library — which is loaded by default at the REPL — is where many of these live and they are documented in one place:

Some of what you’re after is also in the reflection section (and that section includes references to some of these InteractiveUtils, too!)

2 Likes

The following sections of ModernJuliaWorkflows can also be useful:

3 Likes

I’d like to add Cthulhu.jl as a great tool for exploring code.

1 Like

For understanding and/or writing macros there is @macroexpand and dump. And Meta.@lower comes in handy for some investigations.

1 Like