Skip to content
Theory · First program · lesson 6 of 8

Your first function

A cookbook describes a sauce once, on a page of its own. The other recipes do not repeat its steps; they say briefly: "make the sauce". Your own function in a program works the same way: its steps are written in one place, and you can call it from anywhere.

When the same calculation is needed in several places in a program, it is written once—in a separate function. The function add takes two integers and returns their sum:

GO
package main

import "fmt"

func add(a, b int) int {
    return a + b
}

func main() {
    fmt.Println(add(2, 3))   // 5
    fmt.Println(add(10, -4)) // 6
}

Let's follow the first call:

  1. add(2, 3) sends execution into the function add, where a is 2 and b is 3.
  2. The line return a + b computes 5 and returns that number to the place the function was called from.
  3. fmt.Println gets 5 and prints it.

The second call works the same way with other numbers and prints 6.

Press "Next step" and watch control leave main for add and come back with a ready number.

LiveA function call, step by stepstep 1 of 8 · frames: 1

To print the result, main first calls add(2, 3).

A frame is where the variables of one call live

Declaring a function

The line func add(a, b int) int reads left to right:

  • func is the keyword: "I'm declaring a function";
  • add is the function's name;
  • (a, b int) are the parameters, variables that receive values when the function is called; both have the type int, that is, an integer;
  • int after the parentheses is the function's result type.

The return statement ends the function and returns the value of the expression after it. An expression is code that produces a value, such as a + b.

A function can be declared above or below main. The compiler reads the whole package, so the order of declarations in the file does not matter.

The call and its arguments

In the call add(2, 3), the numbers 2 and 3 are the arguments. Here is what happens to them and to the call itself:

  • the arguments go into the parameters in order: 2 into a, 3 into b;
  • the call is replaced by the value the function returned, so you can pass it to fmt.Println;
  • the number of arguments must match the number of parameters: the compiler rejects add(1) with not enough arguments in call to add.

Here the sauce picture stops working. A sauce made by the recipe comes out the same every time. A function, though, gets its own arguments on every call, and its result depends on them.

Order of evaluation

One expression can hold several operators and calls. Let's look at three lines:

GO
fmt.Println(1 + 2*3)           // 7
fmt.Println((1 + 2) * 3)       // 9
fmt.Println(add(add(1, 2), 3)) // 6

The first two lines follow the rules for operators, and the third follows the rule for nested calls. Let's take both rules apart.

Operators

The operators +, - and * work with integers. These rules set their order:

  • as in math, * is evaluated before + and -;
  • parentheses change that order;
  • spaces do not affect the order: 1 + 2*3 and 1+2 * 3 give the same result.

Writing 2*3 without spaces only hints to the reader that the multiplication runs first. By these rules, the first two lines of the example are computed like this:

  1. 1 + 2*3: 2*3 runs first, and 1 + 6 gives 7.
  2. (1 + 2) * 3: the parentheses make 1 + 2 run first, and 3 * 3 gives 9.

Nested calls

A function call can also be an argument of another call. Then the inner call runs first, and its result becomes the argument of the outer one.

In the third line of the example, it goes like this:

  1. add(1, 2) returns 3.
  2. add(3, 3) returns 6.
  3. fmt.Println prints only 6.

Common mistake

The function prints the sum instead of returning it, and it has no result type:

GO
package main

import "fmt"

func add(a, b int) {
    fmt.Println(a + b)
}

func main() {
    fmt.Println(add(2, 3)) // ✗
}
TEXT
add(2, 3) (no value) used as value

A function without a result type returns nothing, so its call cannot be passed to fmt.Println. The fix is to put int after the parentheses and return the sum with return, as in the first example.

Key points

  • Parameters with their types go in the parentheses after the function name, and the result type goes after the parentheses.
  • return ends the function, and the call is replaced by the value it returned.
  • * runs before + and -, and an inner call runs before the outer one.
  • A function without a result type returns nothing, and its call cannot be passed to fmt.Println.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way