# Functions

Author

Marie-Hélène Burle

Functions are objects containing a set of instructions.
When you pass a tuple of argument(s) (possibly an empty tuple) to them, you get one or more values as output.

## Operators

Operators are functions and can be written in a way that shows the tuple of arguments more explicitly.

For instance, you can use the addition operator (`+`) in 2 ways:

``````3 + 2
+(3, 2)``````
``5``

The multiplication operator can be omitted when this does not create any ambiguity:

``````a = 3;
2a``````
``6``

Julia has “assignment by operation” operators:

``````a = 2;
a += 7    # this is the same as a = a + 7``````
``9``

There is a left division operator:

``2\8 == 8/2``
``true``

Julia supports fraction operations:

``4//8``
``1//2``
``1//2 + 3//4``
``5//4``

## Function definition

There are 2 ways to define a new function:

### Long form

``````function <name>(<arguments>)
<body>
end``````

Example:

``````function hello1()
println("Hello")
end``````
``hello1 (generic function with 1 method)``

### Assignment form

``<name>(<arguments>) = <body>``

Example:

``hello1() = println("Hello")``
``hello1 (generic function with 1 method)``

The function `hello1` defined with this terse syntax is exactly the same as the one we defined above.

### Stylistic convention

Julia suggests to use lower case without underscores as function names when the name is readable enough.

## Calling functions

Since you pass a tuple to a function when you run it, you call a function by appending parentheses to its name:

``hello1()``
``Hello``

Here, our function does not take any argument, so the tuple is empty.

## Arguments

### No argument

Our function `hello1` does not accept any argument. If we pass an argument, we get an error message:

``hello1("Bob")``
``LoadError: MethodError: no method matching hello1(::String)``

### One argument

To define a function which accepts an argument, we need to add a placeholder for it in the function definition.

So let’s try this:

``````function hello2(name)
println("Hello name")
end``````
``hello2 (generic function with 1 method)``
``hello2("Bob")``
``Hello name``

Mmm … not quite … this function works but does not give the result we wanted.

Here, we need to use string interpolation:

``````function hello3(name)
println("Hello \$name")
end``````
``hello3 (generic function with 1 method)``

`\$name` in the body of the function points to `name` in the tuple of argument.

When we run the function, `\$name` is replaced by the value we used in lieu of `name` in the function definition:

``hello3("Bob")``
``Hello Bob``

Here is the corresponding assignment form for `hello3`:

``hello3(name) = println("Hello \$name")``
``hello3 (generic function with 1 method)``

Note that this dollar sign is only required with strings. Here is an example with integers:

``````function addTwo(a)
a + 2
end``````
``addTwo (generic function with 1 method)``

And the corresponding assignment form:

``addTwo(a) = a + 2``
``addTwo (generic function with 1 method)``
``addTwo(4)``
``6``

### Multiple arguments

Now, let’s write a function which accepts 2 arguments. For this, we put 2 placeholders in the tuple passed to the function in the function definition:

``````function hello4(name1, name2)
println("Hello \$name1 and \$name2")
end``````
``hello4 (generic function with 1 method)``

This means that this function expects a tuple of 2 values:

``hello4("Bob", "Pete")``
``Hello Bob and Pete``

See what happens when you pass no argument, a single argument, or three arguments to this function.

### Default arguments

You can set a default value for some or all arguments. In this case, the function will run with or without a value passed for those arguments. If no value is given, the default is used. If a value is given, it will replace the default.

Example:

``````function hello5(name="")
println("Hello \$name")
end``````
``hello5 (generic function with 2 methods)``
``hello5()``
``Hello ``
``hello5("Bob")``
``Hello Bob``

Another example:

``````function addSomethingOrTwo(a, b=2)
a + b
end``````
``addSomethingOrTwo (generic function with 2 methods)``
``addSomethingOrTwo(3)``
``5``
``addSomethingOrTwo(3, 4)``
``7``

## Returning the result

In Julia, functions return the value(s) of the last expression automatically.
If you want to return something else instead, you need to use the `return` statement. This causes the function to exit early.

Look at these 5 functions:

``````function test1(x, y)
x + y
end

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

function test3(x, y)
x * y
x + y
end

function test4(x, y)
return x * y
x + y
end

function test5(x, y)
return x * y
return x + y
end

function test6(x, y)
x * y, x + y
end``````

Without running the code, try to guess the outputs of:

``````test1(1, 2)
test2(1, 2)
test3(1, 2)
test4(1, 2)
test5(1, 2)
test6(1, 2)``````

Now, run the code and draw some conclusions on the behaviour of the return statement.

## Anonymous functions

Anonymous functions are functions which aren’t given a name:

``````function (<arguments>)
<body>
end``````

In compact form:

``<arguments> -> <body>``

Example:

``````function (name)
println("Hello \$name")
end``````
``#11 (generic function with 1 method)``

Compact form:

``name -> println("Hello \$name")``
``#13 (generic function with 1 method)``

### When would you want to use anonymous functions?

This is very useful for functional programming (when you apply a function—for instance `map`—to other functions to apply them in a vectorized manner which avoids repetitions).

Example:

``map(name -> println("Hello \$name"), ["Bob", "Lucie", "Sophie"]);``
``````Hello Bob
Hello Lucie
Hello Sophie``````

## Pipes

`|>` is the pipe in Julia.
It redirects the output of the expression on the left as the input of the expression on the right.

The following 2 expressions are equivalent:

``````println("Hello")
"Hello" |> println``````

Here is another example:

``sqrt(2) == 2 |> sqrt``
``true``

## Function composition

You can pass a function inside another function:

``<function2>(<function1>(<arguments>))``

`<arguments>` will be passed to `<function1>` and the result will then be passed to `<function2>`.

An equivalent syntax is to use the composition operator `∘` (in the REPL, type `\circ` then press tab):

``(<function2> ∘ <function1>)(<arguments>)``

Example:

``````# sum is our first function
sum(1:3)``````
``6``
``````# sqrt is the second function
sqrt(sum(1:3))``````
``2.449489742783178``
``````# This is equivalent
(sqrt ∘ sum)(1:3)``````
``2.449489742783178``

Write three other equivalent expressions using the pipe.

Another example:

``````exp(+(-3, 1))

(exp ∘ +)(-3, 1)``````
``0.1353352832366127``

Try to write the same expression in another 2 different ways.

## Mutating functions

Functions usually do not modify their argument(s):

``a = [-2, 3, -5]``
``````3-element Vector{Int64}:
-2
3
-5``````
``sort(a)``
``````3-element Vector{Int64}:
-5
-2
3``````
``a``
``````3-element Vector{Int64}:
-2
3
-5``````

Julia has a set of functions which modify their argument(s). By convention, their names end with `!`

The function sort has a mutating equivalent sort!:

``````sort!(a);
a``````
``````3-element Vector{Int64}:
-5
-2
3``````

If you write functions which modify their arguments, make sure to follow this convention too.

To apply a function to each element of a collection rather than to the collection as a whole, Julia uses broadcasting.

Let’s create a collection (here a tuple):

``a = (2, 3)``
``(2, 3)``

If we pass `a` to the string function, that function applies to the whole collection:

``string(a)``
``"(2, 3)"``

In contrast, we can broadcast the function string to all elements of a:

``broadcast(string, a)``
``("2", "3")``

An alternative syntax is to add a period after the function name:

``string.(a)``
``("2", "3")``

Here is another example:

``````a = [-3, 2, -5]
abs(a)``````
``ERROR: MethodError: no method matching abs(::Array{Int64,1})``

This doesn’t work because the function `abs` only applies to single elements.

By broadcasting `abs`, you apply it to each element of `a`:

``broadcast(abs, a)``
``(2, 3)``

The dot notation is equivalent:

``abs.(a)``
``(2, 3)``

It can also be applied to the pipe, to unary and binary operators, etc.

Example:

``a .|> abs``
``(2, 3)``

Try to understand the difference between the following 2 expressions:

``````abs.(a) == a .|> abs
abs.(a) .== a .|> abs``````
``(true, true)``

## Multiple dispatch

In some programming languages, functions can be polymorphic (multiple versions exist under the same function name). The process of selecting which version to use is called dispatch.

There are multiple types of dispatch depending on the language:

• Dynamic dispatch: the process of selecting one version of a function at run time.
• Single dispatch: the choice of version is based on a single object.

This is typical of object-oriented languages such as Python, C++, Java, Smalltalk, etc.

• Multiple dispatch: the choice of version is based on the combination of all operands and their types.

This the case of Lisp and Julia. In Julia, these versions are called methods.

## Methods

Running `methods(+)` let’s you see that the function `+` has 206 methods!

Methods can be added to existing functions.

``````abssum(x::Int64, y::Int64) = abs(x + y)