Strange way to recover performance with polymorphic types

Las time we checked, I think it was doing to about 16. There is there somewhere in this thread.

But that works for effectively Union types. Following the code above, these are some alternatives:

  1. Annotate the output of extent:
function area2(fig::Figure)
    lower, upper =  extent(fig.shape)::Tuple{Vector3,Vector3}
    sum = 0.
    for i in 1:1000
        sum += (upper[1]-lower[1]) * (upper[2]-lower[2])
    end
    sum
end

which gives:

julia> figure = Figure("1", Box(1,1,1))
Figure("1", Box(1.0, 1.0, 1.0))

julia> @btime area2($figure)
  1.020 μs (1 allocation: 64 bytes)
4000.0
  1. Making Figure concrete:
struct FigureConcrete{Shape}
    label::String
    shape::Shape
end

function area3(fig)
    lower, upper =  extent(fig.shape)
    sum = 0.
    for i in 1:1000
        sum += (upper[1]-lower[1]) * (upper[2]-lower[2])
    end
    sum
end

which gives:

julia> figure = FigureConcrete("1", Box(1,1,1))
FigureConcrete{Box}("1", Box(1.0, 1.0, 1.0))

julia> @btime area3($figure)
  954.727 ns (0 allocations: 0 bytes)
4000.0
  1. Using the union types:
struct UnionFigure
    label::String
    shape::Union{Box, Circle, SBox, SCircle, Triangle}
end

which gives:

julia> figure = UnionFigure("1", Box(1,1,1))
UnionFigure("1", Box(1.0, 1.0, 1.0))

julia> @btime area3($figure)
  960.619 ns (0 allocations: 0 bytes)
4000.0

(this one will work well to ~16 types of shapes, as far as I remember)

Whenever possible I would go with (2).

(the example as it is is probably not the best one, it would be more realistic probably if extent was called in the loop. Then the type instability is harder. You would get here:

area_figure(tup) = (tup[2][1]-tup[1][1]) * (tup[2][2]-tup[1][2])

function area4(fig)
    sum = 0.
    for i in 1:1000
        sum += area_figure(extent(fig.shape))
    end
    sum
end
julia> figure = UnionFigure("1", Box(1,1,1))
UnionFigure("1", Box(1.0, 1.0, 1.0))

julia> @btime area4($figure)
  955.478 ns (0 allocations: 0 bytes)
4000.0

julia> figure = FigureConcrete("1", Box(1,1,1))
FigureConcrete{Box}("1", Box(1.0, 1.0, 1.0))

julia> @btime area4($figure)
  959.455 ns (0 allocations: 0 bytes)
4000.0

julia> figure = Figure("1",Box(1,1,1))
Figure("1", Box(1.0, 1.0, 1.0))

julia> @btime area4($figure)
  43.847 μs (3000 allocations: 93.75 KiB)
4000.0

1 Like