Your best bet is always to benchmark. Here's how I make such decisions:
# The type-based system:
julia> immutable Container1{T}
val::T
end
julia> inc(::Int) = 1
inc (generic function with 1 method)
julia> inc(::Float64) = 2
inc (generic function with 2 methods)
julia> inc(::UInt8) = 3
inc (generic function with 3 methods)
julia> vec = [Container1(1), Container1(1.0), Container1(0x01)]
3-element Array{Container1{T},1}:
Container1{Int64}(1)
Container1{Float64}(1.0)
Container1{UInt8}(0x01)
julia> function loop_inc1(vec, n)
s = 0
for k = 1:n
for item in vec
s += inc(item.val)
end
end
s
end
loop_inc1 (generic function with 1 method)
# The dictionary solution
julia> immutable Container2
code::Symbol
end
julia> vec2 = [Container2(:Int), Container2(:Float64), Container2(:UInt8)]
3-element Array{Container2,1}:
Container2(:Int)
Container2(:Float64)
Container2(:UInt8)
julia> dct = Dict(:Int=>1, :Float64=>2, :UInt8=>3)
Dict(:Int=>1,:UInt8=>3,:Float64=>2)
julia> function loop_inc2(vec, dct, n)
s = 0
for k = 1:n
for item in vec
s += dct[item.code]
end
end
s
end
loop_inc2 (generic function with 1 method)
# The switch solution
julia> function loop_inc3(vec, n)
s = 0
for k = 1:n
for item in vec
if item.code == :Int
s += 1
elseif item.code == :Float64
s += 2
elseif item.code == :UInt8
s += 3
else
error("Unrecognized code")
end
end
end
s
end
loop_inc3 (generic function with 1 method)
julia> loop_inc1(vec, 1)
6
julia> loop_inc2(vec2, dct, 1)
6
julia> loop_inc3(vec2, 1)
6
julia> @time loop_inc1(vec, 10^4)
0.002274 seconds (10.17 k allocations: 167.025 KB)
60000
julia> @time loop_inc1(vec, 10^5)
0.025834 seconds (100.01 k allocations: 1.526 MB)
600000
julia> @time loop_inc2(vec2, dct, 10^5)
0.010278 seconds (6 allocations: 192 bytes)
600000
julia> @time loop_inc3(vec2, 10^5)
0.001561 seconds (6 allocations: 192 bytes)
600000
So in terms of run time, the bottom line is:
- The "switch" version is fastest (by quite a lot), but ugly.
- The dictionary is intermediate. You would likely be able to do even better
with a "perfect hash" dictionary, see
http://stackoverflow.com/questions/36385653/return-const-dictionary
- The type-based solution is slowest, but not much worse than the dictionary.
Note that none of this analysis includes compilation time. If you're writing a
large system, the type-based one in particular will require longer JIT times,
whereas the first two get by with only a single type and hence will need much
less compilation.
Of course, if `inc` were a complicated function, it might change the entire
calculus here. That's really the key: what's the tradeoff between the amount of
computation per element and the price you pay for dispatch to a type-
specialized method? There is no universal answer to this question.
Best,
--Tim