Subroutines: procedures and functions - 1


A subroutine is a separate part of the program that has a name and solves its own separate task. The subroutine is located at the beginning of the main program and can be launched (called) from the main program by specifying the name

The use of subroutines allows you to avoid code duplication, in case you need to write the same code in different places in the program. 
Libraries that are imported into a program (for example, the math library math) consist of subroutines that have already been compiled by someone. Programmers do not need to think about what algorithms they implement, but simply apply them, thinking only about what exactly they are doing. This is a big time saver. There is no need to write an algorithm that has already been written by someone else.

Each routine should only do one thing:  either just calculate something, or output some data, or do something else. 

There are two types of subroutines - proceduresand functions

Subroutines perform some actions, such as printing the result to the screen in a certain form (a simple example, the statement writeln() is a standard subroutine that prints to screen information)

Function subroutines return a result (number, character string, etc.) that we can use in the main program.

Let's try to write a simple procedure:
Suppose we need to display the string "Error" on the screen every time an error can occur in the code due to the fault of the user (for example, when he enters incorrect data)
This can be done by writing the statement
writeln('Error');
And now imagine that such a line needs to be inserted in many places in the program. Of course, you can just write it everywhere. But this solution has two drawbacks.
1) this string will be stored in memory many times
2) if we want to change the output on error, we will have to change this line throughout the program, which is rather inconvenient

For such cases, procedures are needed.
A program with a procedure might look like this:
...
using namespace std;

procedure printError(); // procedure description
begin
    writeln('Error'); // procedure body - commands that the procedure will execute
end;

// main program
start;
...
  printerror(); // start the procedure for execution. We just specify the name of the procedure we want to execute.
...
  printerror();
...
end.

The procedure begins with the word procedure. After the name of the procedure, parentheses are written, which indicate the variables and their types on which the execution of the procedure depends. For example:

var a, b, answer: integer;
procedure Sum(a, b: integer);
begin
    answer := a + b;
end;

All statements that are executed in a procedure are indented. 

Procedures are written before the main program

To execute a procedure, in the main program you need to call it by name and remember to write parentheses!
You can call a procedure in a program any number of times.

Now let's imagine that we need to display different messages in response to a user's error, depending on what kind of mistake he made.
In this case, you can write your own procedure for each error:  
procedure printErrorZero();
begin
    writeln('Error. Division by zero!');
end;

procedure printErrorInput();
begin
    writeln('Error in input!');
end;

What if there are many more possible errors? This solution will not suit us!
We need to learn how to control the procedure by telling it what error message to display.
To do this, we need parameters that we will write in parentheses after the procedure name
procedure printError(s: string);
begin
    writeln(s);
end;
In this procedure, s is a parameter - a special variable that allows you to control the procedure.
The parameter is a variable that determines how the subroutine works. Parameter names are listed separated by semicolons in the subprogram header. After the parameter, a colon is followed by its type.

Now, when calling the procedure, you need to indicate in brackets the actual value that will be assigned to the parameter (variable s) inside our procedure
printError('Error! Division by zero!');
This value is called an argument.
The argument is the parameter value that is passed to the subroutine when it is called.
An argument can be not only a constant value, but also a variable or an arithmetic expression.

It is often necessary to use additional variables that will only be used in the subroutine. Such variables are called local (or local) and can only be manipulated within the subroutine in which they are created.
 
Local variable scope is the function or procedure within which it is declared

Thus, it is possible to limit the scope (scope) of a variable only to the subroutine where it is really needed. In programming, this technique is called encapsulation  - hiding a variable from being changed from outside.

If it is necessary to declare a variable that would be visible anywhere in the program (in any subroutine), then such variables are declared outside of all subroutines (see program 3 from the table below)
Such variables are called global.

Analyze three programs: is displayed on the screen
1) In this program, the variable i is local. A local variable is declared inside a subroutine 2) Here, even if there is a variable i in the main program (with value 7), a new local variable i with value 5 will be created. 
When you run this program, the screen will display the value 75
3) This program has a global variable i. Its value can be changed inside a subroutine, and inside the main program
The procedure will work with the global variable i and it will be assigned a new value equal to 2. The value 2
procedure test();
var i: integer;
begin
    i := 5;
    writeln(i);
end;
var i: integer;

procedure test();
var i: integer;
begin
    i := 5;
    writeln(i);
end;

begin
    i := 7;
    write(i);
    test();
end.
var i: integer;

procedure test();
begin
    i := 2;
end;

begin
    test();
    writeln(i);
end.

Problem: write a procedure that swaps the values ​​of two variables.
The peculiarities of this task are that we need the changes made in the procedure to become known to the calling program.

Let's try to write the procedure like this:

var x, y: integer;
procedure Swap(a, b: integer); // with such a description of the procedure parameters,
var c: integer;
begin // will copy the values ​​of the arguments (x and y)
                      // variables a and b are independent variables not related to x and y
c := a;
a := b;
b := c;
end;

begin
  x := 1;
  y := 2;
  Swap(x, y); //values ​​of variables x and y (arguments) are copied into parameters a and b
  writeln('x = ', x, ', y = ', y); // x=1, y=2
end.
If you run this program, you can see that the values ​​of the variables x and y have not changed. In order for the parameters to change the values ​​of the arguments, you must use passing data by reference. To do this, after the name of the data type in the header of the subroutine, you must put the word var 
procedure Swap(var a, b: integer);   // now variables a and b get addresses of variables x and y in memory
var c: integer; 
begin
c := a;
a := b;
b := c;
end;
Usage: If you pass an argument by reference, then only the variable name (NOT a number and NOT an arithmetic expression) can be in this place when calling the procedure!

DO NOT call a procedure like this:
Swap(x, 4);
Swap(5+x, y);