abstract type AbstractFoo{T}; end
struct SomeFoo <: AbstractFoo{Integer}
field1::Integer
field2::Vector{Integer}
end
struct OtherFoo <: AbstractFoo{Float64}
field1::Float64
field2::Vector{Float64}
field3::Dict{Symbol, Float64}
end
Is it somehow possible to use the Integer & Float64 from the first line of the type definition in the field types? i.e., something like (obviously not working)?
struct SomeFoo <: AbstractFoo{T} where T=Integer
field1::T
field2::Vector{T}
end
Alternatively, any other way of enforcing all of the fields containing T to be equal to Integer, by typing it only once?
or any other function, which necessarily needs an Integer as field1. As I have a lot of Foos, I would like to make sure that I do not make some sort of âtypoâ and create
struct OneMoreFoo <: AbstractFoo{Integer}
field1::Float64
end
by mistake. Therefore I am looking for a coding pattern, which disallows this.
While your solution does solve the issue, SomeFoo is actually a parametric type, while I would like to have it parameter-less.
Maybe the cleanest solution is to create a macro, which does this for me.
@Rafâs solution does not conflict with this goal: in fact, it prevents âtyposâ of this kind, and as for the first problem, you can still restrict with an appropriate method signature, or check the type inside the function with @assert or a type assertion ::Integer.
I have checked some of my code, and found out that the proposed solution fails on a lot of cases of this form
abstract type AbstractFoo{T}; end
Base.@kwdef struct SomeFoo{T<:Integer} <: AbstractFoo{T}
field::Vector{T} = Vector{T}()
end
julia> sf = SomeFoo()
ERROR: UndefVarError: T not defined
julia> sf = SomeFoo{Integer}()
SomeFoo{Integer}(Integer[])
The point is that the proposed solution only works because it is able to infer the type of SomeFoo automatically. If I do
Base.@kwdef struct OtherFoo <: AbstractFoo{Integer}
field2::Vector{Integer} = []
end
julia> of = OtherFoo()
OtherFoo(Integer[])
everyhing works nicely, but I have the Integer there multiple times again.
The solution through the type assertions could work as well, but it would be much nicer if the automatic type assertions checked this for me, without me having to hard-code all of them.
The keyword function is run in a different scope, so It doesnât âseeâ the T. You need to use a specific type in the default value, on the right hand side of the =.\
To get around that, define a constructor with default value as a kw arg.
True. Do you have any idea how to do this? This approach
julia> Base.@kwdef struct SomeFoo{T<:Integer} <: AbstractFoo{T}
field::Vector{T} = []
end
julia> sf = SomeFoo()
ERROR: MethodError: no method matching SomeFoo(::Array{Any,1})
fails and the other possibility of
julia> Base.@kwdef struct OtherFoo{T<:Integer} <: AbstractFoo{T}
field::Vector{T} = Integer[]
end
julia> of = OtherFoo()
OtherFoo{Integer}(Integer[])
is again using the Integer inside the fields, which did not help.
Can you give me an example? I feel like this does not solve the duplicite Integer issue, rather only pushes the problem to the constructor, but maybe I am wrong.
You can get Integer from SomeFoo.var.ub but itâs still going to be a bit of boilerplate. And you can put that in the kwdef too. I was imagining you could do it for AbstractFoo but its not so easy.