Can this be done with an outer constructor?

I recently had a desire for this type of convenience constructor:

# Some generic wrapper
struct AA{T}
       a::T
end
# Create a new wrapper of same inner type
AA{T}(a...) where T = AA(T(a...))

# Dummy to wrap
struct AAA
    a
end

julia> aa = AA(AAA(3))
AA{AAA}(AAA(3))

julia> at = typeof(aa)
AA{AAA}

julia> at(5) # Does not seem to be dispatched to the outer constructor :(
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type AAA
Closest candidates are:
  convert(::Type{T}, ::T) where T at essentials.jl:171
  AAA(::Any) at none:3
Stacktrace:
 [1] AA{AAA}(::Int64) at .\none:3
 [2] top-level scope at none:0

It works with inner constructors though:

struct BB{T}
    a::T

    BB(a::T) where T = new{T}(a)
    BB{T}(a...) where T = new{T}(T(a...))
end

julia> bb = BB(AAA(3))
BB{AAA}(AAA(3))

julia> bt = typeof(bb)
BB{AAA}

julia> bt(5)
BB{AAA}(AAA(5))

Anything missing to make the outer constructor case work?

This is how it is handled by the docs. Basically you have to suppress the default constructors somehow…


struct AA{T} 
    a::T
    function AA(a::T) where T
        new{T}(a)
    end
end
# Create a new wrapper of same inner type
AA{T}(a...) where T = AA(T(a...))

# Dummy to wrap
struct AAA
    a
end

julia> aa = AA(AAA(3))
AA{AAA}(AAA(3))

julia> at = typeof(aa)
AA{AAA}

julia> at(5)
AA{AAA}(AAA(5))
2 Likes

Thanks,

I was hoping I would not have to do that, but I guess that it has to do with how the default constructor is defined.