Functions

How to use functions to write better programs

Imagine you are writing the software for a video game. In this game, players are able to buy and drive cars. There are:

  1. A red Jaguar

  2. A blue Camaro

  3. A green Wrangler

So far you've written the program that makes the red Jaguar work: your player can enter and exit the Jaguar, and they can drive around their virtual city. You wrote the program and everything works.

Great!

But there's just one little problem: now you need to write the programs for the blue Camaro and the green Wrangler. You already know how to do this (the red Jaguar works!), but you'll need to copy-paste all the code you wrote for the red Jaguar, and edit each line to make it work for the blue Camaro and the green Wrangler, and you are definitely not looking forward to this.

This is where functions come in.

A function is a re-usable piece of a program. It can be written just once, then used over and over again.

To solve your video game problem, all you would need to do is... write functions to do everything the red Jaguar already does (door open, door close, engine start, drive, engine stop) and use these functions for the blue Camaro and the green Wrangler. You would finish the game much sooner, and you won't have to copy-paste your old code and read each line to make it work for any new cars.

A function is a re-usable piece of a program. It can be written just once, then used over and over again.

In this section, we will use functions to make our most complex program yet. Our program is a ticketing system (similar to the ones used in cinemas) that will sell tickets to customers. Children and teenagers will be charged $1 for admission, and adults will have to pay $2.

We will learn how to split our programs into functions effectively, as well as how to re-use functions.

To start things off, we will write the first draft of our program:

let age = 10
let price = 0 // this represents $0

if (age < 18) {
    price = 1
} else {
    price = 2
}

print(price)
// outputs 1

If you're having trouble understanding this program, you'll need to pause here and read the sections on Variables and Conditionals.

This seems easy enough, but if we need to extend our program, we'll begin to do a lot of copy-pasting. For example, if we want to charge teens $1.50, we'll need this:

let age = 14
let price = 0 // this represents $0

if (age < 13) {
// if the customer is a child
    price = 1
} else {
    if (age > 12 and age < 20) {
    // if the customer is a teenager
        price = 1.5
    } else {
    // if the customer is an adult
        price = 2
    }
}

print(price)
// outputs 1.5

Now our program is a little bit larger and much more complex than before, but if we look closely, we'll see that we are basically doing the same thing for each kind of customer, and if we need to give a discount to senior citizens (aged 60 years or more), we'll need another if...else statement to set the price.

Using Functions to Avoid Duplicating Code

It is considered very bad form to duplicate bits of code when we need them in multiple places. The answer to this is to write the code in one place, using a function, and then call that function in all the places that we need it.

A function is created by using the func keyword.

func sayName() {
    print("My name is Frodo Baggins")
}

This creates a function called sayName. Each time we call sayName, our program will output "My name is Frodo Baggins".

The func keyword tells the computer that we are about to create a function. The func keyword can only be used to create functions.

After func, we give the function a name. The name we choose must be easy to understand. It must also describe what the function will do when it is called.

The parentheses after the function's name are very important. We will see how in a bit.

Finally, the curly braces ("{" and "}") tell the computer that everything that comes in-between is part of the function's body (the "body" of a function refers to all the code that the function represents. Wherever the function is called, these codes are executed as if they were written right there.)

Calling the sayName Function

Calling a function in Sonar is as easy as writing the function's name, followed by two opposite parentheses.

func sayName() {
    print("My name is Frodo Baggins")
}

sayName()
// outputs "My name is Frodo Baggins"

Now sayName() can be called several times to outputs Frodo's name whenever we need to.

Using Arguments to Give Our Functions Superpowers

In programming, an argument is a value that we give to our functions to make them more powerful and re-usable.

To illustrate, imagine we need to write a program to show the name of every Lord of the Rings character. We could write:

func sayFrodoName() {
    print("My name is Frodo Baggins")
}
func saySamwiseName() {
    print("My name is Samwise Gamgee")
}
func sayPippinName() {
    print("My name is Pippin Took")
}

sayFrodoName()
saySamwiseName()
sayPippinName()

// outputs
// My name is Frodo Baggins
// My name is Samwise Gamgee
// My name is Pippin Took

For just three characters, we've already used up 13 lines, and in all three functions, we are basically doing the same –– outputing the name of the character.

We can take this a step further by condensing all three functions to one, and using an argument to receive the name of the character into the function and show its name.

An argument is just a way to send data into a function so that the function can use it as if it is a variable that was declared inside it.

func sayCharacterName(character_name) {
    print("My name is", character_name)
}

sayCharacterName("Frodo Baggins")
sayCharacterName("Samwise Gamgee")
sayCharacterName("Pippin Took")

// outputs
// My name is Frodo Baggins
// My name is Samwise Gamgee
// My name is Pippin Took

By using an argument called character_name, we have successfully reduced our main program from 13 lines to 7.

Let's see what exactly is going on here:

  1. We wrote a function (sayCharacterName).

  2. sayCharacterName expects to be called with one argument (character_name).

  3. within the function (sayCharacterName), character_name can now be used just the same way as any variable declared with the let keyword.

The 'Return' Keyword

One way to think about functions is that they are like separate programs within the larger, original program. They have their own variables (this is called "scoping") and they can even have other functions contained in them.

Since functions are their own separate programs, they need a way to communicate with the outside, larger program. This program-function data exchange is necessary for building truly powerful programs. There are several ways functions communicate with the main program. One of these is the use of the "return" statement.

When the return statement is used, it immediately stops the function from being executed further and returns some value to the main program. An example will make this clearer.

Imagine you need to write a simple calculator that can add, subtract, mulitply and divide two numbers. You might create add,subtract, mulitply and divide functions like these:

func add(num1, num2) {
    return num1 + num2
}
func subtract(num1, num2) {
    return num1 - num2
}
func multiply(num1, num2) {
    return num1 * num2
}
func divide(num1, num2) {
    return num1 / num2
}

// store the result of adding these numbers
let result = add(1, 2)
print(result)
// outputs 3

When the return statement is the last line in a function, it can be safely omitted like this:

func add(num1, num2) {
    num1 + num2
}

let result = add(1, 2)
print(result)
// outputs 3

Last updated