## Syntax

- f(n) = ...
- function f(n) ... end
- n::Type
- x -> ...
- f(n) do ... end

## Remarks

Aside from generic functions (which are most common), there are also built-in functions. Such functions include `is`

, `isa`

, `typeof`

, `throw`

, and similar functions. Built-in functions are typically implemented in C instead of Julia, so they cannot be specialized on argument types for dispatch.

## Anonymous functions

### Arrow syntax

Anonymous functions can be created using the `->`

syntax. This is useful for passing functions to higher-order functions, such as the `map`

function. The below function computes the square of each number in an array `A`

.

```
squareall(A) = map(x -> x ^ 2, A)
```

An example of using this function:

```
julia> squareall(1:10)
10-element Array{Int64,1}:
1
4
9
16
25
36
49
64
81
100
```

### Multiline syntax

Multiline anonymous functions can be created using `function`

syntax. For instance, the following example computes the factorials of the first `n`

numbers, but using an anonymous function instead of the built in `factorial`

.

```
julia> map(function (n)
product = one(n)
for i in 1:n
product *= i
end
product
end, 1:10)
10-element Array{Int64,1}:
1
2
6
24
120
720
5040
40320
362880
3628800
```

### Do block syntax

Because it is so common to pass an anonymous function as the first argument to a function, there is a `do`

block syntax. The syntax

```
map(A) do x
x ^ 2
end
```

is equivalent to

```
map(x -> x ^ 2, A)
```

but the former can be more clear in many situations, especially if a lot of computation is being done in the anonymous function. `do`

block syntax is especially useful for file input and output for resource management reasons.

## Imperative factorial

A long-form syntax is available for defining multi-line functions. This can be useful when we use imperative structures such as loops. The expression in tail position is returned. For instance, the below function uses a `for`

loop to compute the factorial of some integer `n`

:

```
function myfactorial(n)
fact = one(n)
for m in 1:n
fact *= m
end
fact
end
```

Usage:

```
julia> myfactorial(10)
3628800
```

In longer functions, it is common to see the `return`

statement used. The `return`

statement is not necessary in tail position, but it is still sometimes used for clarity. For instance, another way of writing the above function would be

```
function myfactorial(n)
fact = one(n)
for m in 1:n
fact *= m
end
return fact
end
```

which is identical in behaviour to the function above.

## Introduction to Dispatch

We can use the `::`

syntax to dispatch on the type of an argument.

```
describe(n::Integer) = "integer $n"
describe(n::AbstractFloat) = "floating point $n"
```

Usage:

```
julia> describe(10)
"integer 10"
julia> describe(1.0)
"floating point 1.0"
```

Unlike many languages, which typically provide either static multiple dispatch or dynamic single dispatch, Julia has full dynamic multiple dispatch. That is, functions can be specialized for more than one argument. This comes in handy when defining specialized methods for operations on certain types, and fallback methods for other types.

```
describe(n::Integer, m::Integer) = "integers n=$n and m=$m"
describe(n, m::Integer) = "only m=$m is an integer"
describe(n::Integer, m) = "only n=$n is an integer"
```

Usage:

```
julia> describe(10, 'x')
"only n=10 is an integer"
julia> describe('x', 10)
"only m=10 is an integer"
julia> describe(10, 10)
"integers n=10 and m=10"
```

### Optional Arguments

Julia allows functions to take optional arguments. Behind the scenes, this is implemented as another special case of multiple dispatch. For instance, let's solve the popular Fizz Buzz problem. By default, we will do it for numbers in the range `1:10`

, but we will allow a different value if necessary. We will also allow different phrases to be used for `Fizz`

or `Buzz`

.

```
function fizzbuzz(xs=1:10, fizz="Fizz", buzz="Buzz")
for i in xs
if i % 15 == 0
println(fizz, buzz)
elseif i % 3 == 0
println(fizz)
elseif i % 5 == 0
println(buzz)
else
println(i)
end
end
end
```

If we inspect `fizzbuzz`

in the REPL, it says that there are four methods. One method was created for each combination of arguments allowed.

```
julia> fizzbuzz
fizzbuzz (generic function with 4 methods)
julia> methods(fizzbuzz)
# 4 methods for generic function "fizzbuzz":
fizzbuzz() at REPL[96]:2
fizzbuzz(xs) at REPL[96]:2
fizzbuzz(xs, fizz) at REPL[96]:2
fizzbuzz(xs, fizz, buzz) at REPL[96]:2
```

We can verify that our default values are used when no parameters are provided:

```
julia> fizzbuzz()
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
```

but that the optional parameters are accepted and respected if we provide them:

```
julia> fizzbuzz(5:8, "fuzz", "bizz")
bizz
fuzz
7
8
```

### Parametric Dispatch

It is frequently the case that a function should dispatch on parametric types, such as `Vector{T}`

or `Dict{K,V}`

, but the type parameters are not fixed. This case can be dealt with by using parametric dispatch:

```
julia> foo{T<:Number}(xs::Vector{T}) = @show xs .+ 1
foo (generic function with 1 method)
julia> foo(xs::Vector) = @show xs
foo (generic function with 2 methods)
julia> foo([1, 2, 3])
xs .+ 1 = [2,3,4]
3-element Array{Int64,1}:
2
3
4
julia> foo([1.0, 2.0, 3.0])
xs .+ 1 = [2.0,3.0,4.0]
3-element Array{Float64,1}:
2.0
3.0
4.0
julia> foo(["x", "y", "z"])
xs = String["x","y","z"]
3-element Array{String,1}:
"x"
"y"
"z"
```

One may be tempted to simply write `xs::Vector{Number}`

. But this only works for objects whose type is explicitly `Vector{Number}`

:

```
julia> isa(Number[1, 2], Vector{Number})
true
julia> isa(Int[1, 2], Vector{Number})
false
```

This is due to parametric invariance: the object `Int[1, 2]`

is *not* a `Vector{Number}`

, because it can only contain `Int`

s, whereas a `Vector{Number}`

would be expected to be able to contain any kinds of numbers.

### Writing Generic Code

Dispatch is an incredibly powerful feature, but frequently it is better to write generic code that works for all types, instead of specializing code for each type. Writing generic code avoids code duplication.

For example, here is code to compute the sum of squares of a vector of integers:

```
function sumsq(v::Vector{Int})
s = 0
for x in v
s += x ^ 2
end
s
end
```

But this code *only* works for a vector of `Int`

s. It will not work on a `UnitRange`

:

```
julia> sumsq(1:10)
ERROR: MethodError: no method matching sumsq(::UnitRange{Int64})
Closest candidates are:
sumsq(::Array{Int64,1}) at REPL[8]:2
```

It will not work on a `Vector{Float64}`

:

```
julia> sumsq([1.0, 2.0])
ERROR: MethodError: no method matching sumsq(::Array{Float64,1})
Closest candidates are:
sumsq(::Array{Int64,1}) at REPL[8]:2
```

A better way to write this `sumsq`

function should be

```
function sumsq(v::AbstractVector)
s = zero(eltype(v))
for x in v
s += x ^ 2
end
s
end
```

This will work on the two cases listed above. But there are some collections that we might want to sum the squares of that aren't vectors at all, in any sense. For instance,

```
julia> sumsq(take(countfrom(1), 100))
ERROR: MethodError: no method matching sumsq(::Base.Take{Base.Count{Int64}})
Closest candidates are:
sumsq(::Array{Int64,1}) at REPL[8]:2
sumsq(::AbstractArray{T,1}) at REPL[11]:2
```

shows that we cannot sum the squares of a lazy iterable.

An even more generic implementation is simply

```
function sumsq(v)
s = zero(eltype(v))
for x in v
s += x ^ 2
end
s
end
```

Which works in all cases:

```
julia> sumsq(take(countfrom(1), 100))
338350
```

This is the most idiomatic Julia code, and can handle all sorts of situations. In some other languages, removing type annotations may affect performance, but that is not the case in Julia; only type stability is important for performance.

## Recursive functions

### Simple recursion

Using recursion and the ternary conditional operator, we can create an alternative implementation of the built-in `factorial`

function:

```
myfactorial(n) = n == 0 ? 1 : n * myfactorial(n - 1)
```

Usage:

```
julia> myfactorial(10)
3628800
```

### Working with trees

Recursive functions are often most useful on data structures, especially tree data structures. Since expressions in Julia are tree structures, recursion can be quite useful for metaprogramming. For instance, the below function gathers a set of all heads used in an expression.

```
heads(ex::Expr) = reduce(∪, Set((ex.head,)), (heads(a) for a in ex.args))
heads(::Any) = Set{Symbol}()
```

We can check that our function is working as intended:

```
julia> heads(:(7 + 4x > 1 > A[0]))
Set(Symbol[:comparison,:ref,:call])
```

This function is compact and uses a variety of more advanced techniques, such as the `reduce`

higher order function, the `Set`

data type, and generator expressions.

## Square a number

This is the easiest syntax to define a function:

```
square(n) = n * n
```

To call a function, use round brackets (without spaces in between):

```
julia> square(10)
100
```

Functions are objects in Julia, and we can show them in the REPL as with any other objects:

```
julia> square
square (generic function with 1 method)
```

All Julia functions are generic (otherwise known as polymorphic) by default. Our `square`

function works just as well with floating point values:

```
julia> square(2.5)
6.25
```

...or even matrices:

```
julia> square([2 4
2 1])
2×2 Array{Int64,2}:
12 12
6 9
```