Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do type annotations improve or hinder performance for abstract types?

Tags:

types

julia

The Julia documentation seems to be conflicting about when to use type annotations.

From the Types documentation:

The :: operator can be used to attach type annotations to expressions and variables in programs. There are two primary reasons to do this:

  1. [...]
  2. To provide extra type information to the compiler, which can then improve performance in some cases.

From Performance Tips:

Type annotation will not enhance (and can actually hinder) performance if the type is abstract, or constructed at run-time.

For the purposes of illustration, suppose I had the following hierarchy:

abstract type Character end
struct SpaceMarine <: Character end
# I've used the abstract type Character as a type annotation.
svetlana :: Character = SpaceMarine() 

Is using type annotations the way I did (note that it's abstract), hindering performance or helping it?

In this case, svetlana can only be a subtype of Character, which is the behaviour that I require.

Just as in C# or Java, you can do Character svetlana = new SpaceMarine(), svetlana can only be any subtype of Character.

If using type annotations is hurting performance, how can I keep svetlana a type of Character?

I don't want someone to write svetlana = "Space Marine". In this case, it's now a String.


1 Answers

In my view, and given the illustration, it is neutral.

I find it often easier to benchmark this type of question because I can then make it more pertinent to the problem at hand. Below is a short example based on the illustration given in the question. Only I added a field because otherwise, Julia will optimize away operations on the Struct.

using BenchmarkTools

abstract type C end
struct S <: C 
    f 
end

function ttest(n)
    t1::C =S(0)
    i = 0
    for i in 1:n
        t1 = S(i)
    end
    return t1
end
function stest(n)
    t1::S =S(0)
    i = 0
    for i in 1:n
        t1= S(i)
    end
    return t1
end

@benchmark ttest(1000000)
@benchmark stest(1000000)

and this gives the following for the Abstract Type version:

BenchmarkTools.Trial: 532 samples with 1 evaluation.
 Range (min … max):  8.891 ms …  10.661 ms  ┊ GC (min … max): 0.00% … 10.87%
 Time  (median):     9.057 ms               ┊ GC (median):    0.00%
 Time  (mean ± σ):   9.393 ms ± 499.180 μs  ┊ GC (mean ± σ):  4.06% ±  5.19%

       █▅                                                      
  ▃▃▄▆███▇▆▄▃▃▂▂▁▂▁▂▁▁▂▁▂▁▂▁▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▂▁▃▅▅▄▇▅▆▅▄▃▂▂▂ ▃
  8.89 ms         Histogram: frequency by time        10.2 ms <

 Memory estimate: 15.25 MiB, allocs estimate: 999489.

And this for Struct version:

BenchmarkTools.Trial: 533 samples with 1 evaluation.
 Range (min … max):  8.841 ms …  10.213 ms  ┊ GC (min … max): 0.00% … 11.04%
 Time  (median):     9.048 ms               ┊ GC (median):    0.00%
 Time  (mean ± σ):   9.381 ms ± 494.894 μs  ┊ GC (mean ± σ):  4.04% ±  5.18%

         ▇█                                                    
  ▂▁▃▃▄▅▆██▇▇▄▃▂▂▁▁▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▂▂▂▅▅▅▇▆▅▅▃▃▃ ▃
  8.84 ms         Histogram: frequency by time        10.2 ms <

 Memory estimate: 15.25 MiB, allocs estimate: 999489.

From there, it seems to me that both versions behave similarly about performance.

I used Julia 1.6.3; this behavior might be different in another version. However, it is straightforward to test it.

like image 164
call me Steve Avatar answered Sep 15 '25 06:09

call me Steve



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!