The problem with repeated code
Suppose you want to introduce Andy twice in a program. The direct way is to write the print statements each time:
func mainFunction() {
fmt.Println("My name is Andy")
fmt.Println("I code in Python")
fmt.Println("Sorry, I didn't hear you")
fmt.Println("My name is Andy")
fmt.Println("I code in Python")
}
This works, but the introduction now exists in two places. If Andy switches to Go, you must find and edit both copies, and you will sooner or later edit one and forget the other. The longer the repeated code, the worse this gets.
The idea: write it once, call it many times
A function gives a block of code a name. You define the block once, then run it by calling the name wherever you need it:
func introduceYourself() {
fmt.Println("My name is Andy")
fmt.Println("I code in Python")
}
Every call to introduceYourself() runs both print statements. This brings three benefits:
- Less code. Two calls take two short lines, however long the body is.
- Easier reading. A well-chosen name tells the reader what happens without making them read the details.
- One place to change. Edit the body once and every call picks up the change.
With no return type written after the parentheses, the function returns nothing. It only does its work.
When to reach for a function
A good sign is the same lines appearing twice. Even two copies are worth a function if the block is more than a line or two, and three copies almost always are. Another sign is a block you can describe in a few words, such as "print the introduction". Those words make a good function name.
A function does not have to be reused to be useful. Giving a block a name can make a long function easier to follow, since the reader sees introduceYourself() and doesn't need to read the lines behind it unless they want to.
The exercise, step by step
The starter code has a mainFunction with a comment for each introduction and a line in between that prints Sorry, I didn't hear you.
- Define
introduceYourselfwhere the comment says the function goes. Usefunc, the name, empty parentheses and braces. - Print the name inside the braces with
fmt.Println("My name is Andy"). - Print the language on the next line, still inside the function:
fmt.Println("I code in Python"). - Make the first call in
mainFunction, below the first comment. The name and parentheses run both lines. - Make the second call below the last comment, after the line that prints
Sorry, I didn't hear you. The same two lines print again, and the code behind them is not repeated.
The solution in Go
// Function goes here:
func introduceYourself() {
fmt.Println("My name is Andy")
fmt.Println("I code in Python")
}
func mainFunction() {
// Introduce yourself the first time:
introduceYourself()
fmt.Println("Sorry, I didn't hear you")
// Introduce yourself again:
introduceYourself()
}
The output is the introduction, the apology and the introduction again:
My name is Andy
I code in Python
Sorry, I didn't hear you
My name is Andy
I code in Python
Go details to notice:
- Declaration order is free.
introduceYourselfwould work just as well if it were written belowmainFunction, because package-level declarations can refer to each other in any order. Inside a body, though, statements run from top to bottom. - Parentheses make the call.
introduceYourselfalone is only a reference to the function, and Go rejects it as an unused value. - Comments start with
//and run to the end of the line. They don't change what the program does. - Names are case-sensitive.
IntroduceYourselfwould be a different, exported name.
Common mistakes
- Defining the function but never calling it. The body doesn't run, and nothing is printed.
- Calling it only once. The point of the exercise is to use one definition twice.
- Calling it in the wrong spot. The second call comes after the apology line, so moving it changes the order of the output.
- Copying the print lines into
mainFunction. The output may look right, but the repetition the function was meant to remove is back. - Opening the brace on a new line. In Go the
{stays on the header line.
Key takeaways
- A function lets you write a block of code once and run it as often as you like.
- Each call runs the entire body.
- Changing the body changes the behaviour of every call.
- Define with
func name() { ... }and call withname().