Metaprogramming: macro creating types

Hi,

I’ve been struggling with making a macro that will define a new wrapper type for me, with some minimal functions to make the wrapper type function more/less the same as the type it waps.

For now have the minimal wrapper for Dict (of which the interface specs seem to be missing from the documentation):

macro WrapsDict(MyDict)
    return quote
        ## type
        struct $MyDict{K,V} <: AbstractDict{K,V} 
            d::Dict{K,V}
        end
        ## constructor
        $MyDict(itr...) = $MyDict(Dict(itr...))
        ## minimal methods
        Base.iterate(d::$MyDict, state...) = iterate(d.d, state...)
        Base.length(d::$MyDict) = length(d.d)
        Base.get(d::$MyDict, k, v) = get(d.d, k, v)
    end
end

When I run this code, as @WrapsDict(Dictionary), the type construction and constructor definitions work, but in the definition of the methods, it seems that the newly defined type is unknown at that moment:

ERROR: ArgumentError: invalid type for argument d in method definition for iterate 

I suspect that this is a scope or hygiene problem that I can’t wrap my head around.

A concrete instantiation of the code above, without the macro and with Dictionary replacing $MyDict, does everything as expected.

Any ideas if this can be solved? Thanks!

You need to escape MyDict:

julia> macro WrapsDict(MyDict)
    MyDict = esc(MyDict)
    return quote
        ## type
        struct $MyDict{K,V} <: AbstractDict{K,V} 
            d::Dict{K,V}
        end
        ## constructor
        $MyDict(itr...) = $MyDict(Dict(itr...))
        ## minimal methods
        Base.iterate(d::$MyDict, state...) = iterate(d.d, state...)
        Base.length(d::$MyDict) = length(d.d)
        Base.get(d::$MyDict, k, v) = get(d.d, k, v)
    end
end
@WrapsDict (macro with 1 method)

julia> @WrapsDict(Foo)

julia> Foo((:a => 1, :b => 2))
Foo{Symbol, Int64} with 2 entries:
  :a => 1
  :b => 2

Thanks! I tried escaping $MyDict in various sub-expressions, but to no avail. I couldn’t have imagined the solution would be so simple.

1 Like