I am confused about how namespaces are being applied in the following code, and would appreciate some help.
module A
using LinearAlgebra
abstract type AbsType end
struct SubType <: AbsType end
macro newmethod()
quote
function A.Diagonal(S::A.SubType) end
end
end
@newmethod
function Diagonal(S::AbsType) end # this should be a different function
end
What I expect: the Diagonal defined in the module A should be different from the one in LinearAlgebra, as the function was neither explicitly imported nor was the method defined by specifying the namespace.
Why is there a method LinearAlgebra.Diagonal(S::Main.A.AbsType)? I didn’t ask for this.
This only happens if the method definition Diagonal(S::AbsType) comes after the macro call @newmethod, and this seems to add a new method to LinearAlgebra.Diagonal instead of to A.Diagonal.
I’m not sure what actually happens here, but it seems the module qualification A. in the macro somehow serves to override the explicit import requirement. Perhaps because LinearAlgebra.Diagonal is available in the A module, and the definition is qualified with a module name?
Anyway, depending on what you want to achieve, you should perhaps escape the function name:
macro newmethod()
quote
function esc(Diagonal)(S::A.SubType) end
end
end
or the entire quote:
macro newmethod()
quote
function Diagonal(S::A.SubType) end
end |> esc
end
to avoid macro hygiene renaming it to something like #1#Diagonal.
I’m actually trying to debug a scenario where this worked accidentally when it shouldn’t have, so I’m not really looking for a workaround. In my use case, the last function should have been defined as
function LinearAlgebra.Diagonal(S::AbsType) end
but, perplexingly, this worked without the qualification, which seems like a bug?
I do want all the Diagonals to refer to the LinearAlgebra one, especially the one inside the macro. Moreover, the macro is intended to be used downstream, and I don’t want to assume that LinearAlgebra is loaded at the macro call site. So, ideally, I want to use A.Diagonal to refer to LinearAlgebra.Diagonal within the macro, which is guaranteed to be defined.
The first suggestion above doesn’t appear to work:
julia> module A
using LinearAlgebra
abstract type AbsType end
struct SubType <: AbsType end
macro newmethod()
quote
function esc(Diagonal)(S::A.SubType) end
end
end
@newmethod
function Diagonal(S::AbsType) end
end
WARNING: replacing module A.
ERROR: syntax: invalid function name "#90#esc(A.Diagonal)" around REPL[1]:11
Stacktrace:
[1] top-level scope
@ REPL[1]:15
Perhaps I’m misunderstanding how this is meant to be used.
The second solution does answer the original question, as it correctly defines Diagonal within A.
It would still be good to understand what’s happening in the original case, though.