You just need to add a method
function Base.getproperty(a::Abstract, field::Symbol)
field === :x && return getfield(a, :x)::Float64
error("unknown field ", field)
end
and then you don’t need the type-assert on get_value. getfield is a builtin, so there’s only one such method.
@jules, I know you said you don’t want to consider union-splitting, but do keep in mind you can accelerate your code for some known types and then have a slower path for any extensions. For example,
function test_fast(cs)
x = 0.0
for c in cs
val = isa(c, ConcreteA) ? c.x :
isa(c, ConcreteB) ? c.x :
isa(c, ConcreteC) ? c.x :
isa(c, ConcreteD) ? c.x :
isa(c, ConcreteE) ? c.x : c.x
x += val
end
x
end
doesn’t “lose” anything because that final c.x will handle any type outside the five listed. It is also by far the fastest option yet: if I increase the size of cs by another 100x, I get
julia> @time test(cs)
0.129554 seconds (5.00 M allocations: 76.294 MiB, 7.95% gc time)
5.0e6
julia> @time test_fast(cs)
0.017303 seconds (1 allocation: 16 bytes)
5.0e6
While that isa block might look useless (all options just call c.x), what you’ve done is provide multiple call sites, and the compiler can optimize each one of them differently.