Functions
Compartmentalizing your code for reuse
A common theme you have seen throughout this section is avoiding rewriting the same code multiple times. Functions are the key to achieving this in programming. A function is a way of organizing code that enables a programmer to reuse it. They are useful because once the code to complete a task has been written once, you can reuse that code to complete the same task anywhere you want with a single line that “calls” (runs) the function.
Note: Functions are self-contained, which means any code executed within the function won’t influence anything outside the function. We call this a black box because everything inside the function is obscured from the outside code. It simply sees input go in and output come out.

This is especially useful when collaborating in teams. If programmer A writes a function and programmer B needs to use it, programmer B does not need to understand how it works. They only need to understand what inputs to give the function and what outputs come out of it; none of the inner processes or code matters to programmer B.
Functions are composed of 4 components:
  • The function itself - The syntax used to denote a function is dependent on the language. In certain languages, you may also need to include additional keywords that describe the function’s behavior, such as the scope of the function (where it can be called from) and the data type of the output.
  • The name of the function - This is used to call (run) the function when you need it.
  • The parameters - Although functions are self-contained, one pipeline to get outside code/variables/data inside the function is to “pass it into” the function through parameters. We go into more depth on how to create this pipeline later in the article.
  • The code block - This is the code that will run every time a function is called.
When a program reaches a function call, the program follows this order of control:
  1. The program exits the current body of code and enters the function.
  2. The code block runs from top to bottom.
  3. Upon finishing the code block or being forced out of the block with the keyword return, the program returns to the original body of code.
  4. Any data returned by the function is used in place of the original function call. All other data is removed from the programmer’s memory.
Let’s define a basic function named
hello_world
that simply prints “Hello World!” and then let’s call the function. Entry points for Java and C++ have been included because functions are defined outside of the normal main function.
Code:
def hello_world():
    print("Hello World!")

hello_world()
Output:
> Hello World!
Code:
public class HelloWorld{
    public static void main(String[] args) {
        hello_world();
    }
     
    public static void hello_world() {
        System.out.println("Hello World!");
    }
}
Output:
> Hello World!
Code:
#include <iostream>

using namespace std;

void hello_world() {
    cout << "Hello World!";
}

int main()
{
    hello_world();

    return 0;
}
Output:
> Hello World!
Common Mistake: If you run your code and nothing is happening, you might have forgotten to call your function! Defining the function does not run the code. Even experienced programmers forget to call their function sometimes(although they realize their mistake quickly).
No parameters were being “passed into” (given to) the above function. Let’s expand it to talk about our favorite foods by adding a parameter for our favorite food and then printing it.
Code:
def hello_world(favorite_food):
    print("Hello World!")
    print("My favorite food is " + favorite_food + ".")

hello_world("pizza")
Output:
> Hello World!
> My favorite food is pizza.
Code:
public class HelloWorld{
    public static void main(String[] args) {
        hello_world("pizza");
    }
     
    public static void hello_world(String favorite_food) {
        System.out.println("Hello World!");
        System.out.println("My favorite food is " + favorite_food + ".");
    }
}
Output:
> Hello World!
> My favorite food is pizza.
Code:
#include <iostream>
#include <string>

using namespace std;

void hello_world(string favorite_food) {
    cout << "Hello World!" << "\n";
    cout << "My favorite food is " << favorite_food << ".";
}

int main()
{
    hello_world("pizza");

    return 0;
}
Output:
> Hello World!
> My favorite food is pizza.
To create and use a parameter, we first needed to give the parameter a name inside the parentheses beside the function definition header. It was
favorite_food
in this case. We then used the parameter
favorite_food
as a variable in the function, adding it to “My favorite food is” like a string. Notice that the function doesn’t determine the value of
favorite_food
. Instead, it is the function call that determines the value.
To use the function and pass a value to the parameter, we called the function, and between the parentheses beside the function call, we specified the parameter’s value. This is when
favorite_food
is given its value.
Our code would throw an error if the value of
favorite_food
isn’t passed through a parameter inside the function call’s parentheses and instead simply defined as a variable outside the function. This is shown below:
Code:
def hello_world(favorite_food):
    print("Hello World!")
    print("My favorite food is " + favorite_food + ".")

favorite_food = "pizza"
hello_world()
Output:
> TypeError: hello_world() missing 1 required positional argument: 'favorite_food'
Code:
public class HelloWorld{
    public static void main(String[] args) {
        String favorite_food = "pizza";
        hello_world();
    }
     
    public static void hello_world(String favorite_food) {
        System.out.println("Hello World!");
        System.out.println("My favorite food is " + favorite_food + ".");
    }
}
Output:
> HelloWorld.java:4: error: method hello_world in class HelloWorld cannot be applied to given types;
hello_world();
^
required: String
found: no arguments
Code:
#include <iostream>
#include <string>

using namespace std;

void hello_world(string favorite_food) {
    cout << "Hello World!" << "\n";
    cout << "My favorite food is " << favorite_food << ".";
}

int main()
{
    string favorite_food = "pizza";
    hello_world();

    return 0;
}
Output:
> error: too few arguments to function ‘void hello_world(std::string)’
hello_world();
^
Although, it is possible to pass a variable as the parameter instead of explicitly using the string “pizza.”
Code:
def hello_world(favorite_food):
    print("Hello World!")
    print("My favorite food is " + favorite_food + ".")

favorite_food = "pizza"
hello_world(favorite_food)
Output:
> Hello World!
> My favorite food is pizza.
Code:
public class HelloWorld{
    public static void main(String[] args) {
        String favorite_food = "pizza";
        hello_world(favorite_food);
    }
     
    public static void hello_world(String favorite_food) {
        System.out.println("Hello World!");
        System.out.println("My favorite food is " + favorite_food + ".");
    }
}
Output:
> Hello World!
> My favorite food is pizza.
Code:
#include <iostream>
#include <string>

using namespace std;

void hello_world(string favorite_food) {
    cout << "Hello World!" << "\n";
    cout << "My favorite food is " << favorite_food << ".";
}

int main()
{
    string favorite_food = "pizza";
    hello_world(favorite_food);

    return 0;
}
Output:
> Hello World!
> My favorite food is pizza.
One last notable property of a function is using the “return” keyword that serves two purposes:
  1. Immediately terminate a function and return to the function call.
  2. Return the data following the return keyword.
When data is returned, it is substituted for that function call. For example, we could write a function that adds two numbers and returns the result (and ignores all code after the return keyword). Then, we can store this result into a variable and print it.
Code:
def add(a, b):
    return a+b

x = 2
y = 3
z = add(x,y)
print(z)
Output:
> 5
Code:
public class add2numbers{
    public static void main(String[] args) {
        int x = 2;
        int y = 3;
        int z = add(x,y);
        System.out.println(z);
    }
     
    public static int add(int a, int b) {
        return a+b;
    }
}
Output:
> 5
Code:
#include <iostream>

using namespace std;

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

int main()
{
    int x = 2;
    int y = 3;
    int z = add(2,3);
    cout << z;

    return 0;
}
Output:
> 5
Note: In Java and C++, the returned data type must be included next to the function name, and each of the parameter data types must be included next to each parameter name. This makes it easy for your IDE to detect possible data type conversion errors (e.g., trying to pass in an integer to a parameter of data type string). Python can’t do this until runtime because they don’t require data types.

If you don’t want your function to return anything, use the “void” keyword.
Here is one last example of a function accomplishing the more complex task of calculating the factorial of
num
:
Code:
def factorial(num):
    ans = 1;
    for i in range(1, num + 1):
        ans *= i
    return ans

print(factorial(8))
Output:
> 40320
Code:
public class getfactorial{
    public static void main(String[] args) {
        System.out.println(factorial(8));
    }
    public static int factorial(int num){
        int ans = 1;
        for (int i = 1; i <= num; i++){
              ans *= i;
        }
        return ans;
    }
}
Output:
> 40320
Code:
#include <iostream>

using namespace std;

int factorial(int num) {
    int ans = 1;
    for (int i = 1; i <= num; i++){
        ans *= i;
    }
    return ans;
}

int main()
{
    cout << factorial(8);

    return 0;
}
Output:
> 40320
Why use functions?
Functions are the key to abstraction (the idea that we hide unnecessary code) in computer programming. Breaking a program down into functions makes them simpler to manage, easier to test, and better to reuse. In the absence of functions, programs would contain a lot of unnecessary duplicate code, would lack separation of utility, and be a nightmare to manage, debug, and test.
Here are the primary benefits of using functions:
  1. Encapsulates and separates tasks - The programmer only needs to know what the code does, not how it does it. Good functions divide code into segments, which splits more extensive programs into smaller pieces.
  2. Increases reusability - Copy and pasting code in programs add unnecessary complexity, maintenance, and introduces more places for the code to accidentally go wrong. Functions not only allow you to reuse the code anywhere in your program, but it also allows other programmers to reuse your code.
  3. Makes testing and debugging much easier - Without functions, programs would be much more challenging to understand and debug. When programs are divided into functions, programmers can “test once, deploy everywhere,” substantially reducing testing time. In addition, functions increase readability, making them easier to maintain and follow.
  4. Divides data and logic - Functions help separate steps from actual data. Functions execute code independent of the data passed in. This can help keep you reuse short-term variables and prevent unwanted modifications.
  5. Saves time - All programming languages have libraries, which are built-in functions, that you can use to accomplish common tasks that would otherwise take hundreds of lines to achieve. Examples include print statements, basic arithmetic operators, and similar tasks we take for granted. Imagine how much time would be wasted if you had to write all of this from scratch.
Note: The difference between libraries and functions is libraries only contain very commonly used pieces of code and are uneditable. In addition, libraries are guaranteed to be relatively high-quality and previously extensively tested, whereas you write functions- you need to test and refine them yourself.
You can play with all the code we've used in this article on Replit:
Copyright ©2023 Howard County Hour of Code