Chapter 3: Introduction to Functions

Return to all notes

In any language, the function is one of the most important ideas and this chapter is a review of functions with examples in julia. The Julia documentation on functions is a great place for details.

Simple example

A simple example of a julia function is

function sq(x)
  x*x
end

which just returns the square of the argument, called x. An alternative way to do this is the following:

f(x)=x^2

Calling a Function

To call a function, it is much like that of any other language. If we type:

sq(3)

This returns 9, the square of 3 and f(-4) returns 16.

Function Arguments

The function arguments are the numbers or strings or any element that is passed into the function. In the function sq above, the number x is the only argument. We can have more arguments by separating by commands. The (quite unnecessary function) theSum will take two arguments and add the result:

function the_sum(x,y)
  x+y
end

Exercise

Return statement

In the function sq or the_sum the returned value is the last line of the function. If you want to return a value before the last line you can use the return command. The following will return true if the number is odd and false if the number is true:

function is_odd(n)
  if mod(n,2)==1
    return true
  end
  false
end

The mod function is the remainder of n divided by 2. If the remainder is 1, then the number is odd. On the line return true the code stops here and exits the function and doesn’t execute any of the other lines.

Note: the == tests for equality. This will be discussed later in the course.

A better way to write this (but doesn’t use the return statement) just evaluates if mod(n,2) is 1 or not:

function is_odd(n)
  mod(n,2)==1
end

which will return true if mod(n,2) is actually 1 and false if it is anything else (but the only other possibility is 0).

Specifying Argument Types

The isOdd function above should only work on integers, but if type isOdd(3.5) you get a result. (But does it give you want you want?). What if you put in a string like “hi”?

If instead, you specify a type in the following way:

function is_odd(n::Integer)
   mod(n,2)==1
end

and restart the kernel (either in Jupyter using Kernel->Restart. We’ll talk later about why you need to do this). Check and see what happens if you try isOdd on a non integer or a string.

Exercise

Multiple Dispatch

Before starting this, make sure that you have done the exercise above to write a 2-argument version of the mean and it is currently in the kernel (this means, just run it again, if in doubt.)

A three-argument mean function can be written

function the_mean(x::Number,y::Number,z::Number)
  (x+y+z)/3
end

Depending on the number of arguments, julia will call the appropriate function. This is an example of Multiple Dispatch, in which either the number or type of arguments determine the actual function call.

If you look back at your document when you declared the functions, you should see that the second one entered said the_mean (generic function with 2 methods), which says that there are two functions called mean. Typing methods(the_mean)

results in:

the_mean is a Function.
# 2 methods for generic function "mean":
the_mean(x::Number, y::Number) in Main at In[5]:2
the_mean(x::Number, y::Number, z::Number) in Main at In[6]:2

although you will get different line numbers for the In[??]:2. The important thing is that there are two function definitions.

Multiple dispatch also allows different types of arguments as well. Let’s say we want to create a function mean that take a single string as a argument like:

function the_mean(str::String)
  string("This should return the definition of ",str)
end

and entering it shows you that there are now 3 functions. Try typing mean("definition").

Variable Number of arguments

From the last exercise, it would be unfortunate if we have to write different functions for different number of arguments. We can write a variable number of arguments with a … trailing the last argument. The following is a generalized version of the mean:

function the_mean(x::Number...)
 local i
 local sum=0
 for i=1:length(x)
 sum+=x[i]
 end
 sum/length(x)
end

which uses a for loop that we will discuss later. This function will now find the mean using any number of arguments. Try the_mean(1,2,3) and the_mean(1,2,3,4,5) and determine if it is returning what you expect.

Multiple Return Values

A very nice feature of Julia functions is that of multiple return values. Instead of only being able to return a single number (or requiring to send an array or structural type), you can return more than 1 number (or other data type). For example.

function h(x,y)
  x+y,x-y
end

and if you call this, say h(3,5) you will get the result (8,-2) or if you say

p,q=h(3,5)

the p will take on the value 8 and q will be equal to -2.

Factorial Function

Mathematically, we define the factorial as a function on a non-negative integer as
\[ n! = n(n-1)(n-2)\cdots 3 \cdot 2 \cdot 1 \]

or the product of all of the numbers from itself down to 1. There are a number of ways to program this function as we will see. The following is a way using a for loop

function fact(n::Integer)
    local prod=1
    for i=1:n
        prod *= i
    end
    prod
end

We store the result (product) in a variable called prod and multiply all of the numbers up to n.

Exercise

Recursive Functions

Another type of function is one that calls itself and is called a recursive function. One of the standard examples of this is the factorial function.

Above, we saw how to compute the factorial of a number using a for loop. There’s another way to do this. We can define the factorial in the following way:
$$ n!=\begin{cases}1&n=0\newline n\cdot(n-1)!&\text{otherwise}\end{cases}$$

The big difference is that inside the function is a call to the function. This is what is called a recursive function. Often this is very helpful and the factorial is a great example of this. We can write the factorial this way in the following:

function factr(n::Integer)
   if n == 0
      return 1
   else
      return n*factr(n-1)
   end
end

where n == 0 tests if the variable n is 0 or not.

Exercise

A common recursive function is that of a Fibonacci number. If we let $f(0)=1$, $f(1)=1$, and then
$$ f(n)=f(n-1)+f(n-2)$$. Write a recursive function that produces fibonacci numbers. Test it on small values of $n$.

Variable Scope

If you are using the command line julia (also called the REPL) or iJulia, then entering:

x=6

will create x as a global variable, even without saying so explicitly. If we consider the factorial function above:

function fact(n::Integer)
    prod=1
    for i=1:n
        prod *= i
    end
    prod
end

then recall that n is the function argument and the variable prod is actually declared locally implicitly and it is good form to say it is local by

function fact(n::Integer)
    local prod=1
    for i=1:n
        prod *= i
    end
    prod
end

The variable prod is not defined or visible outside the function. If we type 2*prod for example, an error will occur saying that prod is not defined.

If we have:

x=3
function f()
    local x=2
    x
end
f()

then this will return 2 and typing x (to see it’s value) returns 3, indicating that there are two different x variables.