Reputation: 93
I have an abstract container AbstractContainer
parameterised over a type T
which indicates the type of what is in the container. Every subtype (in this case FloatContainer
) then specifies what's actually in the container (in this case a Float64
).
Ideally I'd have a means of getting back what type is in the container if I only have the container type.
This way I could use it in another struct (in this example MultiplyBy
)
I was thinking of doing it in a similar way to Julia's internal eltype
function but I can't get it to work.
I always get a method error (see the last snippet for the detailed error message)
abstract type AbstractContainer{T} end
gettype(::Type{AbstractContainer{T}}) where T = T
struct FloatContainer <: AbstractContainer{Float64}
x::Float64
end
struct MultiplyBy{T<:AbstractContainer}
x::gettype(T)
end
function process(m::MultiplyBy, v::AbstractContainer)
return typeof(v)(m.x*v.x)
end
function main()
x = FloatContainer(2.0)
y = FloatContainer(3.0)
op = MultiplyBy{FloatContainer}(y)
z = process(op, x)
println(z.x)
end
main()
ERROR: LoadError: MethodError: no method matching gettype(::TypeVar)
Closest candidates are:
gettype(!Matched::Type{AbstractContainer{T}}) where T at /Users/.../test.jl:6
I must admit I'm very new to Julia but I'm very interested in learning more about it. So any tips are appreciated - either on how to solve this problem differently or where my mistake is.
Upvotes: 3
Views: 150
Reputation: 6976
Your gettype
does not work because it dispatches on abstract types, but your container objects will all have concrete types. You have to use the subtype operator in order to dispatch correctly.
Compare dispatch on abstract types:
julia> eltype1(::Type{AbstractContainer{T}}) where T = T
eltype1 (generic function with 1 method)
julia> eltype1(FloatContainer)
ERROR: MethodError: no method matching eltype1(::Type{FloatContainer})
Closest candidates are:
eltype1(::Type{AbstractContainer{T}}) where T at REPL[4]:1
Stacktrace:
[1] top-level scope at REPL[5]:1
julia> eltype1(AbstractContainer{Float64})
Float64
with dispatch on subtypes of abstract types:
julia> eltype2(::Type{<:AbstractContainer{T}}) where T = T
eltype2 (generic function with 1 method)
julia> eltype2(FloatContainer)
Float64
julia> eltype2(AbstractContainer{Float64})
Float64
eltype
callsCalling eltype
directly is usually unnecessary; you can make the parametric type explicit during dispatch.
This solution uses only parametric types:
julia> struct Container{T}
x::T
end
julia> struct MultiplyBy{T}
x::T
end
julia> MulitplyBy(x::Container{T}) where T = MultiplyBy{T}(x.x)
MulitplyBy (generic function with 1 method)
julia> process(m::MultiplyBy, x::Container{T}) where T = Container{T}(m.x * x.x)
process (generic function with 1 method)
julia> a = Container(2.0)
Container{Float64}(2.0)
julia> b = Container(3.0)
Container{Float64}(3.0)
julia> op = MulitplyBy(b)
MultiplyBy{Float64}(3.0)
julia> process(op, a)
Container{Float64}(6.0)
Upvotes: 3
Reputation: 1313
i'm not sure about what you need, but i coded an working example with your structure:
abstract type AbstractContainer{T} end
#not necessary anymore
#gettype(a::Type{AbstractContainer{T}}) where T = T
struct FloatContainer{T<:AbstractFloat} <: AbstractContainer{T} #AbstractFloat, to include Float32, BigFloats and others
x::T
end
#you can't use functions on struct definitions, if you need more restrictions,
#use a Constructor
struct MultiplyBy{T<:AbstractContainer}
x::T
end
#example external Constructor
MultiplyBy(x::AbstractFloat) = MultiplyBy(FloatContainer(x))
value(x::AbstractContainer) = x.x #basic accesor function
value(x::MultiplyBy) = value(x.x)
function process(m::MultiplyBy, v::AbstractContainer)
return typeof(v)(value(m)*value(v)) #calling accesor functions to access the values.
end
function main()
x = FloatContainer(2.0)
y = FloatContainer(3.0)
op = MultiplyBy(y) #the parametric type is inferred automatically, no need to use Curly Braces
z = process(op, x)
println(value(x)) #better use accesor functions that direct access, as the underlying implementation can change
end
main()
Upvotes: 0