# there are many ways to represent a model in julia
# tuple
# very efficient
# not flexible
# error-prone
model = (0.96, 0.1, 0.3, 4)
(0.96, 0.1, 0.3, 4)
model[1] # julia is 1-based indexing
0.96
model[1] = 3
MethodError: no method matching setindex!(::Tuple{Float64, Float64, Float64, Int64}, ::Int64, ::Int64)
The function `setindex!` exists, but no method is defined for this combination of argument types.

Stacktrace:
 [1] top-level scope
   @ In[4]:1
 [2] eval(m::Module, e::Any)
   @ Core ./boot.jl:489
sizeof(model)
32
sizeof(0.64)
8
# use a dictionary
# less error-prone
# instead of strings we use symbols
"a"
"a"
:a
:a
model2 = Dict(
:α => 0.3, # pair
:β => 0.96,
:γ => 4,
:δ => 0.1
)
Dict{Symbol, Real} with 4 entries:
  :α => 0.3
  :γ => 4
  :δ => 0.1
  :β => 0.96
model2[:α]
0.3
# dict are mutable
model2[:α] = 0.4
0.4
# doesn't have a predetermined representation in memory
isbits(model2)
false
# create a special julia-object: a struct
struct AModel
    α
    β
    γ
    δ
end
# create a model
mm = AModel(0.3, 0.96, 4, 0.1)
AModel(0.3, 0.96, 4, 0.1)
sizeof(mm) # we have an efficient object
32
# we can access fields with .
mm.α  # human friendly
0.3
mm[1] # it doesn't behave like a vector of parameters
MethodError: no method matching getindex(::AModel, ::Int64)
The function `getindex` exists, but no method is defined for this combination of argument types.

Stacktrace:
 [1] top-level scope
   @ In[26]:1
 [2] eval(m::Module, e::Any)
   @ Core ./boot.jl:489
struct BModel
    α::Float64
    β::Float64
    γ::Float64
    δ::Float64
end

# structures are good type optimization

##

# namedtuples are great
# named arguments (with name=) on the right of ;
p = (;α=0.3, β=0.96, γ=4, δ=0.1)
(α = 0.3, β = 0.96, γ = 4, δ = 0.1)
α = p.α
δ = p.δ
# unpack tuples
α, β, γ, δ = tt
# keyword unpacking
(;α, δ)=tt
# equivalent to 
# α = p.α
# δ = p.δ
(α = 0.3, β = 0.96, γ = 4, δ = 0.1)
isbits(tt)
true
# behave like tuples
tt[1]
0.3
# fields can be accessed with .
tt.α
0.3
### functions
# strings:
"afkjh"
# triple quotes for multiline
"""
multi
lines
"""
"multi\nlines\n"
""" This is the docstring

a, b positional

"""
function fun(a,b)
    
    # return explicitly the result
    return a*b
    # the last line is the return value by default
    a+b    
end
fun
fun(3,3)
9
?fun
search: fun run


This is the docstring

a, b positional

# one liners
f(x,y) = (x+y)*exp(x)
f (generic function with 1 method)
f(3,3)
120.51322153912601
# anonymous functions

# parameters are given as tuples
(u,v) -> u^2 + v^2
#2 (generic function with 1 method)
((u,v) -> u^2 + v^2)(0.1,0.3)
0.1
# functions can have optional and keyword arguments
# c is an optional argument
function fadd(a,b,c=1)
    a + b*c
end

# this is equivalent to 
# function fadd(a,b)
#     c=1
#     a + b*c
# end
# function fadd(a,b,c)
#     a + b*c
# end
fadd (generic function with 2 methods)
fadd(1,2)
3
fadd(1,2,3)
7
#kwargs after ;
function fmul(a,b ; twice=false)
    if (twice == false)
        return a + b
    else
        return a + 2*b
    end
end
fmul (generic function with 1 method)
fmul(1,4; twice=true)
9
# functions that modify their arguments
# have ! by convention
### vectors
# "look" like python lists
v = [3,4,2] # enclosed with square brackets
3-element Vector{Int64}:
 3
 4
 2
# behave like numpy arrays
2*v
3-element Vector{Int64}:
 6
 8
 4
# follow mathematical conventions
v .* v # the dot means element by element
3-element Vector{Int64}:
  9
 16
  4
f(x) = x^2
f (generic function with 2 methods)
f.(v)
3-element Vector{Int64}:
  9
 16
  4
v'*v # sacalar product with transpose '
29