# Strange way to recover performance with polymorphic types

**URL:** <https://discourse.julialang.org/t/strange-way-to-recover-performance-with-polymorphic-types/72250>\
**Category:** Performance\
**Tags:** question\
**Created:** [November 29, 2021, 5:23pm UTC](https://discourse.julialang.org/t/strange-way-to-recover-performance-with-polymorphic-types/72250 "2021-11-29T17:23:36Z")\
**Posts on this page:** 1\
**Showing post:** 4

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [November 29, 2021, 6:38pm UTC](https://discourse.julialang.org/t/strange-way-to-recover-performance-with-polymorphic-types/72250/4 "2021-11-29T18:38:31Z")

</div>

Las time we checked, I think it was doing to about 16. There is there somewhere [in this thread](https://discourse.julialang.org/t/union-splitting-vs-c/61772/22).

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

1. Annotate the output of extent:

```julia
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
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:

```julia
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
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:

```julia
struct UnionFigure
    label::String
    shape::Union{Box, Circle, SBox, SCircle, Triangle}
end

```

which gives:

```julia
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:

```julia
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
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

```

---

_[View the full topic](https://discourse.julialang.org/t/strange-way-to-recover-performance-with-polymorphic-types/72250)._
