Functions

The last expression is returned automatically; return is for early exit.

8.1 Defining functions

The last expression is returned automatically; return is for early exit. A function returning nothing returns nothing.

function add(x, y)
    return x + y
end

add(x, y) = x + y                  # one-line (assignment) form

function stats(v)
    m = sum(v) / length(v)
    return m, maximum(v)           # returns a tuple
end
avg, mx = stats([1, 2, 3])

8.2 Optional & keyword arguments

Keyword arguments come after ;. Required keywords: f(; x) = x.

greet(name, greeting="Hello") = "$greeting, $name!"
greet("Ann"); greet("Ann", "Hi")

function plotline(x, y; color="blue", width=1, kwargs...)
    println("color=$color width=$width extra=$(kwargs)")
end
plotline(1, 2; width=3, style=:dash)

color = "red"
plotline(1, 2; color)              # shorthand for color=color

8.3 Varargs & splatting

sumall(args...) = sum(args)
sumall(1, 2, 3)              # 6
v = [1, 2, 3]
sumall(v...)                 # splat a collection into arguments
f(a, b, rest...) = rest

8.4 Anonymous functions & do-blocks

sq = x -> x^2
add = (x, y) -> x + y
map(x -> x * 2, [1, 2, 3])
filter(iseven, 1:10)

map([1, 2, 3]) do x          # do-block syntax: passes the block as the first argument
    x^2 + 1
end

open("out.txt", "w") do io   # resource management idiom
    write(io, "hello")
end

8.5 Higher-order functions & composition

map(sqrt, [1, 4, 9])
reduce(+, 1:5)                 # 15
foldl(-, 1:4), foldr(-, 1:4)
mapreduce(x -> x^2, +, 1:3)    # 14
sum(abs2, [1, -2, 3])          # 14
any(iseven, [1, 3, 4]), all(>(0), [1, 2]), count(isodd, 1:10)
(sqrt ∘ abs)(-16)              # composition \circ<Tab>: 4.0
[1, 4, 9] .|> sqrt             # piping with broadcast
1:5 |> sum                     # pipe operator
>(3)(5)                        # partially applied comparison: true
Base.Fix2(-, 1)(10)            # 9

8.6 Closures

function make_counter()
    count = 0
    return () -> (count += 1)
end
c = make_counter(); c(); c()   # 1, 2

8.7 Argument passing & mutation

Julia uses pass-by-sharing: functions receive references to the same objects. Mutating a mutable argument (array, mutable struct) is visible to the caller; rebinding is not.

function double!(v)            # ! convention: mutates its argument
    v .*= 2
    return v
end
a = [1, 2, 3]; double!(a)      # a == [2, 4, 6]

8.8 Recursion

Julia doesn't guarantee tail-call optimization; use loops for deep iteration.

fib(n) = n < 2 ? n : fib(n - 1) + fib(n - 2)
factorial_rec(n::Integer) = n <= 1 ? one(n) : n * factorial_rec(n - 1)

8.9 Operators are functions

+(1, 2, 3)                     # 6
⊕(a, b) = a + b                # define a new infix operator (\oplus<Tab>)
1 ⊕ 2
Base.:+(a::String, b::String) = a * b   # extend an operator (type piracy — avoid in real code!)