# On programming with Julia

Julia is my favorite programming language for scientific computing. As a dynamically typed language, it compiles efficient native code based on LLVM. This leads to the popular phrase in the Julia community, “walk like Python, run Like C.” The multiple dispatch as a new paradigm for language design makes it natural to write performant and extendable codes.

Although Julia was designed from the beginning for numerical computing, it is unlikely for a beginner to write high-performance codes right out of the box like Fortran and C. In this post, I would like to share some common tips that help you to write performant codes.

## Parameterized structure

Julia’s functions are generic methods. Thanks to the type inference, cumbersome type annotation is not needed for the arguments. For example, the following function

``````time2(x) = 2 * x
``````

is as fast as its annotated version specifically designed for a 64 bit float number

``````time2_an(x::Float64) = 2 * x
``````

However, the same statement does not hold for composite data types. Let us take a look at the following example.

``````using BenchmarkTools
``````
``````struct A
a
b
c
end

struct B{T1,T2,T3}
a::T1
b::T2
c::T3
end
``````
``````a = [A(rand(), rand(), rand()) for i = 1:10000];
b = [B(rand(), rand(), rand()) for i = 1:10000];
``````
``````function add(x)
for i in eachindex(x)
x[i].a + x[i].b + x[i].c
end
end
``````
``````add (generic function with 1 method)
``````
``````@btime add(a)
``````
``````  120.258 μs (10000 allocations: 156.25 KiB)
``````
``````@btime add(b)
``````
``````  2.331 μs (0 allocations: 0 bytes)
``````
``````@code_warntype add(a)
``````
``````Variables
x[36m::Vector{A}[39m
@_3[33m[1m::Union{Nothing, Tuple{Int64, Int64}}[22m[39m
i[36m::Int64[39m

Body[36m::Nothing[39m
[90m1 ─[39m %1  = Main.eachindex(x)[36m::Base.OneTo{Int64}[39m
[90m│  [39m       (@_3 = Base.iterate(%1))
[90m│  [39m %3  = (@_3 === nothing)[36m::Bool[39m
[90m│  [39m %4  = Base.not_int(%3)[36m::Bool[39m
[90m└──[39m       goto #4 if not %4
[90m2 ┄[39m %6  = @_3::Tuple{Int64, Int64}[36m::Tuple{Int64, Int64}[39m
[90m│  [39m       (i = Core.getfield(%6, 1))
[90m│  [39m %8  = Core.getfield(%6, 2)[36m::Int64[39m
[90m│  [39m %9  = Base.getindex(x, i)[36m::A[39m
[90m│  [39m %10 = Base.getproperty(%9, :a)[91m[1m::Any[22m[39m
[90m│  [39m %11 = Base.getindex(x, i)[36m::A[39m
[90m│  [39m %12 = Base.getproperty(%11, :b)[91m[1m::Any[22m[39m
[90m│  [39m %13 = Base.getindex(x, i)[36m::A[39m
[90m│  [39m %14 = Base.getproperty(%13, :c)[91m[1m::Any[22m[39m
[90m│  [39m       (%10 + %12 + %14)
[90m│  [39m       (@_3 = Base.iterate(%1, %8))
[90m│  [39m %17 = (@_3 === nothing)[36m::Bool[39m
[90m│  [39m %18 = Base.not_int(%17)[36m::Bool[39m
[90m└──[39m       goto #4 if not %18
[90m3 ─[39m       goto #2
[90m4 ┄[39m       return nothing
``````
``````@code_warntype add(b)
``````
``````Variables
x[36m::Vector{B{Float64, Float64, Float64}}[39m
@_3[33m[1m::Union{Nothing, Tuple{Int64, Int64}}[22m[39m
i[36m::Int64[39m

Body[36m::Nothing[39m
[90m1 ─[39m %1  = Main.eachindex(x)[36m::Base.OneTo{Int64}[39m
[90m│  [39m       (@_3 = Base.iterate(%1))
[90m│  [39m %3  = (@_3 === nothing)[36m::Bool[39m
[90m│  [39m %4  = Base.not_int(%3)[36m::Bool[39m
[90m└──[39m       goto #4 if not %4
[90m2 ┄[39m %6  = @_3::Tuple{Int64, Int64}[36m::Tuple{Int64, Int64}[39m
[90m│  [39m       (i = Core.getfield(%6, 1))
[90m│  [39m %8  = Core.getfield(%6, 2)[36m::Int64[39m
[90m│  [39m %9  = Base.getindex(x, i)[36m::B{Float64, Float64, Float64}[39m
[90m│  [39m %10 = Base.getproperty(%9, :a)[36m::Float64[39m
[90m│  [39m %11 = Base.getindex(x, i)[36m::B{Float64, Float64, Float64}[39m
[90m│  [39m %12 = Base.getproperty(%11, :b)[36m::Float64[39m
[90m│  [39m %13 = Base.getindex(x, i)[36m::B{Float64, Float64, Float64}[39m
[90m│  [39m %14 = Base.getproperty(%13, :c)[36m::Float64[39m
[90m│  [39m       (%10 + %12 + %14)
[90m│  [39m       (@_3 = Base.iterate(%1, %8))
[90m│  [39m %17 = (@_3 === nothing)[36m::Bool[39m
[90m│  [39m %18 = Base.not_int(%17)[36m::Bool[39m
[90m└──[39m       goto #4 if not %18
[90m3 ─[39m       goto #2
[90m4 ┄[39m       return nothing
``````
``````
``````
``````
``````