Hi,
Is there an updated information for how to create an abstract container type in v0.6?
Here’s the corresponding info for 0.4:
How should I declare “abstract container type” fields?
Is it now recommended to inherit from AbstractArray?
Thanks,
Glen
Hi,
Is there an updated information for how to create an abstract container type in v0.6?
Here’s the corresponding info for 0.4:
How should I declare “abstract container type” fields?
Is it now recommended to inherit from AbstractArray?
Thanks,
Glen
That advice still holds: type-fields used in performance critical parts of a code should have a concrete type. If you want the type-field to hold a range of types you need to parameterize the type.
You can check that yourself (using the linked example):
_
_ _ _(_)_ | A fresh approach to technical computing
(_) | (_) (_) | Documentation: http://docs.julialang.org
_ _ _| |_ __ _ | Type "?help" for help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 0.6.0-dev.2826 (2017-02-14 13:01 UTC)
_/ |\__'_|_|_|\__'_| | Commit 2ecc2157c5* (12 days old master)
|__/ | x86_64-pc-linux-gnu
julia> type MySimpleContainer{A<:AbstractVector}
a::A
end
julia> type MyAmbiguousContainer{T}
a::AbstractVector{T}
end
julia> f(v) = v.a
f (generic function with 1 method)
julia> @code_warntype f(MySimpleContainer([1]))
Variables:
#self#::#f
v::MySimpleContainer{Array{Int64,1}}
Body:
begin
return (Core.getfield)(v::MySimpleContainer{Array{Int64,1}}, :a)::Array{Int64,1}
end::Array{Int64,1} # good
julia> @code_warntype f(MyAmbiguousContainer([1]))
Variables:
#self#::#f
v::MyAmbiguousContainer{Int64}
Body:
begin
return (Core.getfield)(v::MyAmbiguousContainer{Int64}, :a)::AbstractArray{Int64,1}
end::AbstractArray{Int64,1} # bad
That is a very helpful example, thanks. Would you not inherit from AbstractArray to get a bunch of functionality? I thought that was improved in v0.6.
Is there a good way to restrict the element type of v.a to be a subtype of Number and be performant? Similarly, if I try to restrict the eltype with a function call I run into problems:
julia> g{A<:AbstractVector,N<:Number}(m::MySimpleContainer{A{N}}) = "yes"
ERROR: TypeError: Type{...} expression: expected UnionAll, got TypeVar
julia> g(m::MySimpleContainer{A{N}}) where N<:Number where A<:AbstractVector = "yes"
ERROR: TypeError: Type{...} expression: expected UnionAll, got TypeVar
julia> g{A<:AbstractVector}(m::MySimpleContainer{A{<:Number}}) = "yes"
ERROR: TypeError: Type{...} expression: expected UnionAll, got TypeVar
julia> g{A<:AbstractVector}(m::MySimpleContainer{A}) where N<:Number where A <: AbstractVector{N}= "yes"
ERROR: UndefVarError: N not defined
julia> g{A<:AbstractVector}(m::MySimpleContainer{A}) where A<:AbstractVector{N} where N<:Number = "yes"
ERROR: TypeError: Type{...} expression: expected UnionAll, got #g
After reading the manual, I’m not sure how to use the where clause effectively.
Glen
Yes, but that is in 0.5 already (but maybe it improved). (But that is a different topic to the section of the manual you link to). See http://docs.julialang.org/en/stable/manual/interfaces/ for the bits you need to implement additionally.
type MySimpleContainer{A<:Number}
a::A
end
I struggle too
. This seems ok:
g(m::MySimpleContainer{A}) where A<:AbstractVector{N} where N<:Number = "yes"
The type definition and inheritance make things more complicated. I’d like to define a type that has the same constraints as:
g(m::MySimpleContainer{A}) where A<:AbstractVector{N} where N<:Number = "yes"
I’d like to define a container type that inherits from AbstractVector and is limited to Numbers. Like:
struct MySimpleContainer{A} where A<:AbstractVector{N} where N<:Number <: AbstractVector{N}
data::A
end
But where clauses are not allowed in type definitions so I’m not sure what is the best way to do this.
Thanks,
Glen
You mean
julia> struct MySimpleContainer{N<:Number,A<:AbstractVector{N}} <: AbstractVector{N}
end
?
Hi yuyichao,
Thanks for the help. This is pretty exciting as it now works and should be performant:
julia> struct MySimpleContainer{N<:Number,A<:AbstractVector{N}} <: AbstractVector{N}
data::A
end
julia> Base.size(m::MySimpleContainer) = size(m.data)
julia> Base.getindex(m::MySimpleContainer, idx) = getindex(m.data, idx)
julia> MySimpleContainer(data::AbstractVector) = MySimpleContainer{eltype(data),typeof(data)}(data)
MySimpleContainer
julia> MySimpleContainer([1,2,3])
3-element MySimpleContainer{Int64,Array{Int64,1}}:
1
2
3
julia> f(x) = x.data
f (generic function with 1 method)
julia> @code_warntype f(MySimpleContainer([1,2,3]))
Variables:
#self#::#f
x::MySimpleContainer{Int64,Array{Int64,1}}
Body:
begin
return (Core.getfield)(x::MySimpleContainer{Int64,Array{Int64,1}}, :data)::Array{Int64,1}
end::Array{Int64,1}
julia> typeof(MySimpleContainer([1,2,3]))
MySimpleContainer{Int64,Array{Int64,1}}
I wasn’t sure the best way to do the outer constructor but it seems to work.
Is there any way to get a type of the container to be MySimpleContainer{Array{Int64,1}} so Int64 isn’t there twice (it seems kind of redundant).
Glen
No, that is not possible. Related issue: Proposal: Defer calculation of field types until type parameters are known · Issue #18466 · JuliaLang/julia · GitHub