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:
- [...]
- 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
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With