Content of the lesson:
We explained in the previous lesson what are procedures and how can we use them. Functions are very similar; there are only a few differences which will be shown in this lesson.
A function is a separated part of a program which should deal with a problem. Functions are used often in these cases:
You cannot make more complex projects without functions because it is not clever and sometimes also not possible to write all source code inside the begin..end block of the main program.
A function can contain a finite number of commands similarly as a procedure; it can use local and global variables, receive arguments and use them for calculations and can be called from the main part of program or from another function/procedure.
Unlike a procedure it has to return a value. This means an advantage for us because we can use a function directly inside a condition or inside a calculation without the need to send a variable to it to store the result and then use that variable in the main part.
Functions return values of assigned type which means for example an integer, text string, or boolean value (you can also use wilder types like arrays, stacks etc.) but you cannot use a function without return value unlike several other programming languages (several ones can use so called void value).
The syntax of each function is illustrated in the following source code:
Function name (parameters of functions):return value; //parameters are optional var variables //optional declaration of variables for this function begin commands of the function name:=value; //assigning the return value end;
Each function has to begin with the keyword function which is followed by its name. You can also insert parameters into brackets behind the name. The rest of the first line is new, we add a colon and then the type of return value (integer, string, boolean, …). This value has to be returned back at the end of function and can be used by the parrent function (or by the main part of program) which called this function.
The next line with local variables is optional, then you can see the keyword begin and the program part of the function which contains all commands and calculations.
The penultimate line is also new - it sets which value should be
returned. Here you should assign the return value to
the function (use the function as a variable with the same name). The
return value can be assigned directly using a number or text, or you can
assign it using a variable. However, you have to keep the type which was
chosen in the first line, otherwise the program will crash.
Note: assigning the return value to function does not have to be the last
command inside function, you can add commands behind that line.
Definition of each function ends with the keyword end which is followed by a semicolon! Pay attention, programmers often make a mistake here because they forget to add the semicolon.
We will show a very simple function for the beginning to understand the principle of the return value. To simplify all examples, the header part of programs with the name of program and used libraries will not be written because we will not change anything in that part.
function vratpozdrav:string; begin vratpozdrav:='Hello'; end; begin writeln(vratpozdrav); readln; end.
You can see that a function with name vratpozdrav was defined and it only returns the text string Hello. Then this function is used in the main part of program to write the returned value into console. The command writeln(vratpozdrav) does the same as if we wrote writeln(‘Hello‘). The whole program writes the greeting Hello into console and waits until enter key is pressed to be terminated (in case we did not add the line readln we would not be able to read the greeting because the program would be terminated immediately after writing it).
Note that this function does not require any parameters so you do not have to write the empty brackets behind its name.
In case you wanted to use procedures, you would have to change the program like this example:
var pozdrav:string; procedure vratpozdrav; begin pozdrav:='Hello'; end; begin vratpozdrav; writeln(pozdrav); readln; end.
Note that an additional global variable was defined and it will be stored inside memory for the rest of your program.
Now we can show a more advanced example where we will use a local variable to store a result of a calculation and then we will return this value.
function Spocitej:integer; var soucet:integer; begin soucet:=45+54*2; Spocitej:=soucet; end; begin writeln(Spocitej); readln; end.
We created the function Spocitej which saves the result of a fictive formula into the variable soucet and this variable is returned. The result will be written into console in the main part of program.
We can extend the example by using parameters for our function.
var a,b:integer; function Spocitej(var a,b:integer):integer; var soucet:integer; begin soucet:=a+b; Spocitej:=soucet; end; begin a:=40; b:=50; writeln(Spocitej(a, b)); readln; end.
Now you see that the function Spocitej requires two parameters – integer numbers which are added and the result is returned. We had to create two variables to insert them as parameters. Unfortunately, the Pascal language does not allow you to insert values directly as parameters like Spocitej(40, 50) as several other programming languages, you have to save these values to variables at first.
These examples were only an illustration, they did not solve any concrete task. We will show other examples in the following parts of the lesson which might be used in real programs.
The return value is a great advantage especially when you want to check a condition of a result and you simultaneously need the result to be computed. Thanks to functions you do not need any other variables because you can insert a function directly inside a condition in case it returns a boolean value.
Take a look at an example which will add and multiply two numbers and then if both results will be lower than 100 it will write a particular message.
var a,b:integer; function Vynasob(var x,y:integer):boolean; begin if (x*y<100) then Vynasob:=true else Vynasob:=false; end; function Secti(var x,y:integer):boolean; begin if (x+y<100) then Secti:=true else Secti:=false; end; begin a:=8; b:=11; if (Secti(a,b) AND Vynasob(a,b)) then writeln('Sum and product are lower than 100.'); readln; end.
There are two functions defined in this example (Vynasob and Secti). They return boolean value true in case that the sum and the product are lower than 100. We initialize variables at first in the main part and then we use those functions inside a condition to check if the sum and the product are lower than 100. In case that this is true, a message is written - if we use values 8 and 11 the message will be written.
You can see that functions can be arbitrarily used instead of boolean values and they can be connected using logical conjunctions. This is the main difference between functions and procedures and also one of advantages of functions.
Parameters for functions can be inserted using two ways - by values or by addresses. In case you insert a variable by value, the function will take the value or this variable from the brackets at the place where it was called and it will use this value to initialize its own local variable. Any changes which will be done to the local variable will not affect the variable which was inserted into brackets at the place where you called the function.
However, you can get into a situation when you need to change the value of inserted variable inside a function. This procedure can be used when calling a function from other functions and using a global variable might be problematic.
We will illustrate the difference on the following simple examples. We will use procedures instead of functions to avoid dealing with return values (inserting parameters is absolutely identical for functions and procedures).
var cislo:integer; procedure predanihodnotou(a:integer); begin writeln(a); a:=10; writeln(a); end; begin cislo:=5; predanihodnotou(cislo); writeln(cislo); readln; end.
You can see that in the moment when we insert the variable cislo into the procedure its value is 5. The procedure then assigns the value 10 inside the parameter and writes it to console. However, after returning to the main part of program we can see that the variable cislo still contains the value 5. How is it possible? The reason is that we did not add the keyword var when defining parameters of the procedure. The procedure created its own local variable for the parameter and all changes were applied to this local variable. After returning to the main part the local variable is no longer accessible and we continue working with the variable cislo which has not been changed.
var cislo:integer; procedure predaniodkazem(var a:integer); begin writeln(a); a:=10; writeln(a); end; begin cislo:=5; predaniodkazem(cislo); writeln(cislo); readln; end.
After adding the keyword var the situation changed. You can see that the value of the variable cislo was changed inside the function. We did not insert the value of this variable inside the function but we inserted the address of memory where it is stored. The function then worked with this place inside memory and did all changes to the variable cislo. This is the reason why the value 10 was written after returning to the main part of program.
We can show one more example of inserting parameters by addresses. Imagine you are writing a program for a particular shop. You get prices of products (we will use 3 products to simplify the situation) without the tax and you need to sum the prices without and then with a tax (we will use 20 % as the value of tax).
We will create a function which sums the prices, writes the result and also increases the values by the tax. When you will call the function for the second time it will calculate the sum of items with tax. The process of adding tax will be done after calculating the sum so it will not be a problem when calling the function for the second time. It is an unnecessary waste of processor time to increase the values by tax for the second time because you do not need it but this is only a simple example how to insert parameters by addresses.
var a,b,c:extended; function sectiazdan(var a,b,c:extended):extended; begin sectiazdan:=a+b+c; a:=a*1.2; b:=b*1.2; c:=c*1.2; end; begin a:=100; b:=200; c:=300; writeln('Sum of items without tax: ', sectiazdan(a,b,c):0:0); writeln('Sum of items with tax: ', sectiazdan(a,b,c):0:0); readln; end.
It was necessary to use all variables of type extended because we used multiplying by 1,2 in the function sectiazdan. Then we added the notation :0:0 to the line where we output values to console because we want to output the numbers without decimal places. In case we did not add this notation, the result would look like the following one:
You know everything important about functions so you can start creating your own functions. The following examples could also be solved using procedures, try to consider advantages and disadvantages – consider the number of required local and global variables and also the number of required steps to get the same result.
Write a function JeVetsi which will compare two numbers inserted as parameters and will return a boolean value - true in case that the first number is bigger, false in case that the second number is bigger.
Write a function Maximum which will require an arbitrarily large
array of integers as a parameter and will return an integer value. It
will browse through the array and return the maximum value.
Note: initialize the array using random numbers from 1 to 50.
Similar to the previous task, but the function will return the
minimum value.
Note: initialize the array using random numbers from
1 to 50.
Write a function Prumer, which will require an arbitrarily large
array of integers as a parameter. This function will browse through the
array and compute the arithmetic mean of all items. Do not forget that
the arithmetic mean does not have to be an integer number and it should
be quite accurate (ideally rounded to two decimal places).
Note: initialize the array using random numbers from 1 to 50.