A function is a section of code which contains a set of instructions, where the instructions describe how a particular task is to be accomplished. Functions are declared and may then be called one or more times. Declaring a function involves specifying the instructions that the function will contain. When a function is called, it executes those instructions. Functions are fundamental to computer programming in general, and they play a central role in JS++.
Note: This tutorial does not cover external functions in JS++. An external function is declared with the function
keyword and returns an external type. We will examine external functions and external types in Chapter 9. (To preview, an external type is one which isn’t a JS++ type; usually, these will be JavaScript types.) This tutorial examines internal JS++ functions. Internal functions are not declared using the function
keyword, and can return any type.
Before we can use a function to do anything, we have to declare it. So let’s start by looking at how functions are declared. Make a new folder and name it "Functions". Then make a new file and name it "Functions.jspp". Write in the following code:
external $; string getFavoriteAnimalString(string animal) { return "My favorite animal is the " + animal; }
Save Functions.jspp to your Functions folder. The code we have written declares a function named getFavoriteAnimalString
. This name is appropriate, because the function’s purpose is to return a string which states one’s favourite animal. That task is accomplished by the return statement in the function’s body (the part within the curly braces): the return statement evaluates the expression to the right of the return
keyword, and then sends the evaluated expression back to the function’s caller (where it might be assigned to a variable, for example). Since the purpose of getFavoriteAnimalString
is to return a string, we can say that the function’s return type is string
, and we specify this by writing string
to left of the function’s name.
Just as the output of getFavoriteAnimalString
will be a string, it also takes a string input. To compose the string which reports one’s favourite animal, the function needs to know which particular animal is one’s favourite. It receives this input information via the string parameter named animal
, which we write inside the parentheses to the right of the function’s name. When at a later stage of our program we call getFavoriteAnimalString
to get it to execute, we will pass a particular string into its input parameter: the particular string we pass it will be the function’s argument.
Note: The distinction between a function’s parameter(s) and its argument(s) can be confusing. To clarify, a parameter is a variable written when declaring a function. The parameter type specifies what type of input the function takes. An argument, by contrast, is the actual value passed to a function as input when the function is called. The argument becomes the value of the parameter variable.
Before we call getFavoriteAnimalString
, let’s set up an HTML document which we will use to display the result. Make a second file named "Functions.html" and write in the following:
<!DOCTYPE html> <title>Functions program</title> <body> <p id="content"></p> <script src="http://code.jquery.com/jquery-1.12.4.min.js"></script> <script src="Functions.jspp.js"></script> </body> </html>
Save Functions.html to your Functions folder. Now go back to Functions.jspp and write in the following, below the code where you declared getFavoriteAnimalString
:
string favoriteAnimalString = getFavoriteAnimalString("cat"); $("#content").text(favoriteAnimalString);
On the first of these new lines, we call getFavoriteAnimalString
, passing it the string "cat" as its argument. This function call returns the string "My favorite animal is the cat", and we assign this string to the variable favoriteAnimalString
. On the second line, we use jQuery to select the "content" element of Functions.html and to set its text to the value of favoriteAnimalString
. Compile Functions.jspp and then open Functions.html in a browser. If everything has worked, your document should display "My favorite animal is the cat".
In our example, getFavoriteAnimalString
returns a string. In general, however, a JS++ function can return any valid type, so long as the value returned belongs to the return type specified to the left of the function’s name in the declaration.
A function cannot have more than one return type, but it need not return anything at all. If a function does not return anything, it should be declared with the void
keyword:
void displayFavoriteAnimalString(string animal) { string favoriteAnimalString = "My favorite animal is the " + animal; $("#content").text(favoriteAnimalString); }
A void
function can be declared without using a return statement (as in the example above), or it can be declared with the statement return
; which doesn’t evaluate or return any expression.
When a function executes a return statement, it exits immediately. This means that any code written after a return statement will not execute.
Functions can take zero, one, or multiple parameters. If a function takes multiple parameters, then those parameters can be of the same type or different types:
void displayFavoriteAnimalIfLucky(string animal, int number) { string favoriteAnimalString = "My favorite animal is the " + animal; if(number == 7) { $("#content").text(favoriteAnimalString); } }
Note: A function can also take a variadic parameter, which allows the function to take infinitely many arguments for that single parameter. A full understanding of variadic parameters requires an understanding of arrays, however, which won’t be covered until the next tutorial. We will therefore postpone discussion of variadic parameters until then.
A recursive function is one that may call itself during its execution. Here is a well-known example of a recursive function:
int factorial (int input) { if (input <= 1) { return input; } else { return input * factorial(input - 1); } }
The purpose of factorial
is to calculate and return the factorial of the input
parameter. For example, if we call factorial
with an input
of 5, it will return 120.
factorial
illustrates a general structure that is common to many recursive functions. The function handles two sorts of cases differently, depending on the value of the input argument. In the base case, the value of the argument means that the function’s task can be accomplished easily, with little or no further work required. The function therefore returns without any need to call itself. In the recursive case, by contrast, significant further work is required. To accomplish this, the function in some way simplifies or reduces that further work, which involves calling itself with a modified input value. The modified input value will be closer to the value needed to qualify for a base case.
The base case for factorial
comes when the input
argument is less than or equal to 1. In this case, the function simply returns input
. If input
is greater than 1, by contrast, the functions returns input * factorial(input - 1)
. Thus factorial
will repeatedly call itself, with the value of input
decreasing by 1 with each recursive call. When factorial
calls itself with an input
value of 1, that particular recursive call returns, which then enables each of the previous recursive calls to return.
Recursive functions should be used with care. In particular, it is important to ensure that with each recursive call, the value of the input argument moves closer to that needed for the base case. If you don’t do this, there is a danger that you may create infinite recursion: this will cause a runtime error. In addition, it is often more efficient to use an iterative function (i.e. one which uses a loop) rather than recursion. When there is a benefit to using recursion, it usually consists in making one’s code easier to read, rather than increased computational efficiency.
JS++ allows functions to be overloaded. Overloading consists in declaring two functions with the same name, but with different parameter lists. For example, we might overload a function named displayFavoriteAnimalString
as follows:
void displayFavoriteAnimalString(string animal) { string favoriteAnimalString = "My favorite animal is the " + animal; $("#content").text(favoriteAnimalString); } void displayFavoriteAnimalString(string firstAnimal, string secondAnimal) { string favoriteAnimalString = "My favorite animals include the " + firstAnimal + " and the " + secondAnimal; $("#content").text(favoriteAnimalString); }
The compiler allows you to declare two functions with the same name in this way, because of the difference in their parameter lists: the first function takes a single string parameter, whereas the second function takes two. This difference means that when you call one of the two functions, there is no ambiguity as to which is meant: if you supply one string argument then it must be the first function, and if you supply two string arguments then it must be the second.
In the example given, the two overloaded functions have the same return type: void. This isn’t required, however. So long as overloaded functions have different parameter lists, their return types can either be the same or different. You cannot, however, overload functions with the same parameter lists and different return types: this would lead to ambiguity about which function was meant by a caller, so the compiler won’t allow it.
Overloading can make good sense when the overloaded functions perform conceptually similar roles, where this similarity should be obvious from the perspective of the caller. Overloading should not be used where the overloaded functions perform conceptually different roles, since this will make your code harder to understand. One particular technique to avoid if possible is giving overloaded functions different return types: this isn’t considered good coding style.
Consider the following code:
external $; int(int, int) processNumbers = int(int a, int b) { return a + b; };
If you look carefully at this syntax (and do take note of the trailing semi-colon!), you will see that it isn’t the normal syntax of a function declaration. Rather, what we have here is a variable assignment. The variable is named processNumbers
, and its type is specified by the code to the left of the name: int(int, int)
. This is a callback type. A variable of this type can take a function as its value. However, the range of functions which the variable can take is restricted to those whose parameters and return type match those specified by the callback type. So given that processNumbers
has the callback type int(int, int)
, a function can be assigned to processNumbers
only if it takes two int
parameters and returns an int
.
The code to the right of the "=" sign assigns a function expression to process numbers. A function expression differs from a function declaration in that it evaluates to a value (the function expressed). This means that a function expression can be used (as here) in a variable assignment, or passed as an argument to another function, or returned from another function.
The function assigned to processNumbers
is an addition function. It adds the two int
arguments together and returns the result. The assignment is fine, since the addition function has the parameters and return type specified by the variable’s callback type: it takes two int
parameters and returns an int
. Now we can call processNumbers
:
int result = processNumbers(3, 4); $("#content").text(result);
Later on in our program, however, we might decide to assign a different function to processNumbers
:
processNumbers = int(int a, int b) { return a * b; };
This assignment is just as valid as the previous one, since the multiplication function assigned also has the correct parameters and return type: it takes two int
parameters and returns an int
. If we call processNumbers
after assigning this new function to it, the result will differ from the one returned by our earlier call.