I have a data type that stores a vector z and a list of views to that vector, whose index ranges can be specified by the user, here a and b. The views are also accessible via m.a and m.b by overloading getproperty.
Depending on how and where I create those views getproperty is type stable or not. Please see the following MWE:
import Base.hasproperty, Base.getproperty
struct MyStruct{T, ZT <: AbstractVector{T}, VT <: NamedTuple}
z::ZT
v::VT
# function MyStruct(z::ZT, vars) where {ZT}
# # this is type-stable
# v = ( a = view(z, 1:2), b = view(z, 3) )
# # this is not type-stable
# # v = NamedTuple{keys(vars)}(( view(z, idx_range) for idx_range in vars ))
# new{eltype(z), ZT, typeof(v)}(z, v)
# end
end
function MyStruct(z::ZT, vars) where {ZT}
# this is type-stable
# v = ( a = view(z, 1:2), b = view(z, 3) )
# this is also type-stable
v = NamedTuple{keys(vars)}(( view(z, idx_range) for idx_range in vars ))
MyStruct{eltype(z), ZT, typeof(v)}(z, v)
end
function Base.getproperty(x::MyStruct{T, ZT, VT}, s::Symbol) where {T, ZT, VT}
if hasfield(VT, s)
return getfield(x, :v)[s]
else
return getfield(x, s)
end
end
function test()
m = MyStruct(rand(3), ( a = 1:2, b = 3 ))
@time m.z
@time m.a
@time m.b
end
test();
If I have an inner constructor, creating the views statically leads to a type-stable getproperty, but creating them dynamically leads to an unstable getproperty. If I have an outer constructor, both lead to a type-stable getproperty.
I do not quite understand this behaviour. The type parameter VT of MyStruct has the same value in all examples.
I tested this with Julia v1.7.2 and 1.8.0-beta3 on macOS (M1).