Methods and Parameters
A method
bundles up a sequence of useful instructions and assigns it a name. Methods are
an excellent way for software components to communicate.
Most
programming languages provide two types of methods:
Function methods
A function
method takes any number of parameters but returns a single value. A call on a
function method appears as part of an expression. For example:
z = largest(x, y);
Here is the
coding (in Java) for this method:
int largest(int n, int m) {
if (n
> m) {
return
n;
}
else {
return
m;
}
}
The method
begins with the declaration of the return type (int in this example), which also
identifies the method as a function method.
A function
method asks a question – what is the value of something? Information is passed
to the function via its parameters and the answer is returned as the value of
the function.
Procedure methods
A procedure
method has parameters but does not return a value. A call on a procedure method
appears as a distinct statement. For example:
display(x);
A procedure
method carries out an action – some task is carried out. Information is passed
to a method via its parameters, but there is no need for a value to be
returned.
Object Oriented programming.
How is
parameter passing different in OOP? The answer is: not very much. Look at this
method call:
setText(myTextBox, "hello);
which is
a method call in a non-OO situation. In OOP, we simply remove one of the
parameters and make it a prefix:
myTextBox.setText("hello");
Side Effects
Ideally,
communication between a caller and a method is as clear and simple as possible.
The best way of achieving this is to ensure that all the communication takes
place by means of the parameters. This way the communication is obvious.
By
contrast, a poor alternative is the use of side
effects. A side effect is any communication that takes place other than via
parameters. This can happen if the method has direct access to information in
the calling component. For example:
int l;
largest(x, y);
int largest(int n, int m) {
if (n
> m) {
l = n;
}
else {
l = m;
}
}
The problem
here is that neither inspection of the method call or the method header reveals
the side effect. The programming language can eradicate this type of side
effect by enforcing scope rules.
Examples of
side effects carried out by a method are:
Clearly
doing these things is vital in most software! So performing side effects in
mainstream software is absolutely vital. However, in functional programming,
side effects are not possible - functional programming constitutes the purist
kind of programming. Functional programming exhibits referential
transparency. This means that whenever and wherever a method is called, it
always has the same effect. Clearly this is impractical in (normal) imperative
programming.
Parameters
It is
common to distinguish two types of parameter
In call by
value, a copy of the value is passed as the parameter to the method. This means
that the method can use the value, but cannot change the value back in the
caller. Thus, the scheme is very safe.
There can
be a performance problem with call by value, because time and space are
required to copy the value in main memory. This is worse if large objects such
as arrays are passed as parameters. This is also true of a return value. Thus
some programming languages (e.g. Fortran, which is
often used for processing arrays) do not provide call by value.
In call by
reference, the parameter is a pointer to some data. Thus the method can choose
to change the value of the data in the calling component. This can be dangerous
if the user does not expect it.
Some
languages enable the programmer to specify the type of the parameter as either ref or value. This improves clarity and enables the compiler to check for compatible
use. Here, for example, is a method that changes the values of its parameters:
void swap(ref int x, ref int y) {
int temp;
temp =
x;
x = y;
y = temp;
}
Java
confuses the picture. All parameters are passed by value. But there are two
types of entities in Java – primitive entities such as int (which are not objects) and proper
objects. When a primitive entity I passed, its value cannot be changed. When an
object is passed as a parameter, a reference (pointer) to the object is passed.
The pointer itself cannot be changed, but the data items within the object
pointed to can.
Some
languages (e.g. C++) allow the program to change pointers that are passed as
parameters. So a method can change the value of the pointer so as to point to
some other object. This, again, can be dangerous.
Arguably,
thinking about pointers is really a low-level view of programming. A different
approach is to label parameters as in, out or in-out as follows:
in – a value is passed to a method. The method
can use the value but cannot change the value
out – this parameter is used to return a new value
to the caller. The method can assign a value, but cannot use its value.
in-out – the value of the parameter can be used and
its value can be changed.
STQ
Write the
header of a method that finds that sum of its first two integer parameters,
providing the answer as a third parameter
Answer
void sum(in int x, in int, y, out int answer)
End
The purist approach
Following
the influence of functional programming, it is possible to adopt a very pure
attitude to methods and parameters. In functional programming, all parameters
are passed as values (which therefore cannot be changed by the method). Any
information to be passed back to the caller is communicated as a return value.
This prevents any method from changing data in the caller.
Following
this scheme, a purist approach is:
Thus there
is a clear separation of roles between function and procedure methods.
It is not
always easy to adopt this strategy, but usually it is. An example where it is
not possible is a method to interchange the value of two parameters.