macrosjuliamethod-dispatch

Add method to a macro defined in a different package


For example, how could I add, in my own code/package, a method for the @test macro defined in the standard package Test.jl.

Doing the following does not seem to work:

import Test: @test

macro test(ex::SomeArbitraryType,  args...)
    ...
end

More concretely, it does not register an extra method on the actual Test.@test macro, but just defines a new local macro called @test.


Solution

  • You can add new methods, but the types you can dispatch on are limited: Expr, Symbol, literal numbers:

    julia> using Test
    
    julia> @test 1+1==2  # macro called with Expr type
    Test Passed
    
    julia> @which @test 1+1==2
    var"@test"(__source__::LineNumberNode, __module__::Module, ex, kws...)
         @ Test ~/.julia/dev/julia/usr/share/julia/stdlib/v1.12/Test/src/Test.jl:493
    
    julia> function Test.var"@test"(__source__::LineNumberNode, __module__::Module, ex::Int, kws...)
             println("new method for Int")  # more specific signature
             return __module__
           end
    
    julia> @test 3  # macro called with Int type
    new method for Int
    

    If x isa SomeArbitraryType at runtume, this is not visible to the macro. For instance, if we define f(x) = @test x, then the macro method for ::Symbol is called immediately. The macro sees the code involved in defining f, and returns other code which runs once f is called.

    julia> macro Test.test(ex::Symbol,  args...)
             println("method for symbol")
             return string(__source__)
           end
    
    julia> f(x) = @test x  # macro expansion happens immediately
    method for symbol
    f (generic function with 1 method)
    
    julia> f("something")  # now the expanded code is run
    "#= REPL[10]:1 =#"
    
    julia> methods(Test.var"@test")
    # 3 methods for macro "@test" from Test:
     [1] var"@test"(__source__::LineNumberNode, __module__::Module, ex::Symbol, args...)
         @ Main REPL[6]:1
     [2] var"@test"(__source__::LineNumberNode, __module__::Module, ex::Int64, kws...)
         @ Main REPL[4]:1
     [3] var"@test"(__source__::LineNumberNode, __module__::Module, ex, kws...)
         @ ~/.julia/dev/julia/usr/share/julia/stdlib/v1.12/Test/src/Test.jl:493