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:
The program exits the current body of code and enters the
function.
The code block runs from top to bottom.
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.
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.
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.
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:
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.”
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:
Immediately terminate a function and return to the function
call.
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:
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.
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.
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.
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.
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: