3
votes

(Reposted from Julia slack for posterity)

let’s say I have some constants like

const FooConst = 1
const BarConst = 2

and I also have some struct

struct Foo end
struct Bar end

and I now want to define a method for each struct to look up that constant

f(::Type{Foo}) = FooConst
f(::Type{Bar}) = BarConst

how would I achieve that last block using metaprogramming? I'm essentially trying to tack on Const to the end of the name of the Struct and look that up in the code

...

...(this) works outside of a module, but in my module the constants aren't exported. After I import my module, f isn't able to look the constants up. MWE here:

module M
import InteractiveUtils: subtypes
export Foo, Bar, f

abstract type Super end
struct Foo <: Super end
struct Bar <: Super end

const FooConst = 1
const BarConst = 2

for T in subtypes(Super)
    @eval f(::Type{$T}) = $(Symbol(T, "Const"))
end

end # module

and then in my REPL:

julia> using Main.M
julia> f(Foo)
ERROR: UndefVarError: Main.M.FooConst not defined
Stacktrace:
 [1] f(::Type{Foo}) at ./none:11
 [2] top-level scope at none:0

I am however able to access it directly:

julia> Main.M.FooConst
1
1

1 Answers

4
votes

From Mason Protter on Julia slack:

Mason Protter 2:26 PM @Sebastian Rollen The issue was the Symbol(T, "const"). That actually ended up expanding to Symbol("Main.Foo.FooConst") and Symbol("Main.Foo.BarConst") instead of Symbol("FooConst") and Symbol("BarConst") respectively. You can fix that using Symbol(nameof(T), "Const") as shown here:

module M
import InteractiveUtils: subtypes
export Foo, Bar, f

abstract type Super end
struct Foo <: Super end
struct Bar <: Super end

const FooConst = 1
const BarConst = 2

for T in subtypes(Super)
    @eval f(::Type{$T}) = $(Symbol(nameof(T), "Const"))
end

end # module

julia> using .M;  f(Foo)
1

julia> f(Bar)
2

Make sure you restart Julia before running this code or Julia will continue to use the exported functions from the old version of your module.