===================================
Functions, procedures and methods
===================================
The *“Don't Repeat Yourself”* principle requires that a code using two
or more times the same construct should be abstracted into a common
name.
With constants__ this was seen before, one can simply give a name to
the constant value and reuse this name instead of the value throughout
the rest of the code.
.. __: variables.html
The question becomes tricky when it is not a constant but a full
computation that should be abstracted, for example:
.. code:: java
double p1 = 320;
System.out.println(p1 * VAT / 100);
double p2 = 45;
System.out.println(p2 * VAT / 100);
double p3 = 65.30;
System.out.println(p3 * VAT / 100);
Here the entire pattern formed by “``System.out.println(X * VAT /
100)``” should be abstracted and it is not a simple constant.
This is where it becomes time to define a *function* instead.
Functions: the mathematical view
================================
In math we *define* a function for example like this:
:math:`f(x) = x + 1, \quad \forall x\in\mathbb{R}`
or:
:math:`f : \forall x\in\mathbb{R}, f(x) = (x+1) \in\mathbb{R}`
or:
:math:`\begin{array}{l l l}f: \mathbb{R} & \mapsto & \mathbb{R} \\ f: x & \mapsto & x + 1 \end{array}`
When we do this we say “*f* is a function from :math:`\mathbb{R}` to
:math:`\mathbb{R}`, which for every *x* equals *x+1*”. And when we say
this, we specify 5 things:
- the *name* of the function: *f*
- the *parameter* of the function: *x*
- the *domain* of the function (set of the parameter): :math:`\mathbb{R}`
- the *expression* of the function: *x+1*
- the *image* or *range* of the function (set of the result): :math:`\mathbb{R}`
The previous example has the same set as domain and image, but this is
not always so. For example:
:math:`\begin{array}{l l l}g: \mathbb{N}\times\mathbb{N}^* & \mapsto & \mathbb{Q}^+ \\ g: n, m & \mapsto & \frac{n}{m} \end{array}`
This function g has two parameters that are natural numbers, the
second parameter must be non-zero, and associates every pair of
parameters to the positive fractional number resulting from the
division of one by the other.
Once functions are defined in math, it is possible to *use* them
via the notation of “application”, for example “f(3)” or “g(1,2)”
denote respectively the application of *f* on the value 3, and
the application of *g* on the pair (1, 2).
Simple functions: math functions in code
========================================
Each programming language has its own way to define and use functions
in the mathematical sense. In Java, we use the following general
construct:
Syntax:
``(`` :sub:`[` :sub:`[` ``,`` :sub:`]*` :sub:`]` ``)`` ``{`` ``}``
(a type followed by a name followed by an opening parenthesis,
followed by zero or more occurrences of a type followed by a name,
separated by commas, followed by a closing parenthesis)
Semantics:
Defines a function with the name defined on the left before the
opening parenthesis, with the parameters defined within the
parentheses, with the various domains and image set describes by
data types. The image is given by the type on the far left, whereas
the domain set(s) are given by the type(s) between parentheses.
Every time the function is applied (see below), the statements
given on the right will be executed again.
Furthermore, within the “” part on the right,
the special construct is recognized:
Syntax:
``return`` ``;``
(the keyword “``return``” followed by a value followed by a
semicolon)
Semantics:
When this point is reached during execution, the value
on the right becomes the value for the entire function
and the execution of the function stops.
To use this, the following general method applies:
1. ensure you have a good understanding of which mathematical function you want to encode.
2. select a name for the function. Write this, followed by an opening and closing parenthesis.
3. between the parenthesis, write the name of the parameters.
4. in front of every name, select a type that describes the domain of the parameter (see below).
5. in front of the name of the function, select a type that describes the image of the function.
6. encode the expression of the function between the braces ``{`` and ``}``.
For example, the functions *f* and *g* presented above can be encoded as
follows:
.. code:: java
int f(int x)
{
return x + 1;
}
double g(int n, int m)
{
return n / m;
}
Once we have a function in code, we can use it like in math using the
application construct seen in a previous lecture:
Syntax:
``(`` :sub:`[` ``,`` :sub:`]*` ``)``
(A name followed by an opening parenthesis followed by zero
or more values separated by commas, followed by a closing parenthesis.)
Semantics:
when evaluating an expression of this form, the function designated
by the name on the right is invoked using the values between
parentheses as input arguments; when it completes execution, its
return value becomes the value of the entire expression.
For example:
.. code:: java
int y = f(3); // stores 4 in y
double z = g(1, 2); // stores 0.5 in z
Choice of types for functions
=============================
When encoding from math, we encounter the issue that Java data types
do not map exactly to the common sets in calculus. Instead the
following approximation are commonly used:
==================== =====================
Set in maths Type in Java, C, C++
==================== =====================
:math:`\mathbb{N}`` ``int`` (or ``byte``, ``short``, ``long``)
:math:`\mathbb{Z}`` ``int`` (or ``byte``, ``short``, ``long``)
:math:`\mathbb{Q}`` ``double`` (or ``float``)
:math:`\mathbb{R}`` ``double`` (or ``float``)
:math:`\mathbb{B}`` ``boolean``
==================== =====================
Functions with effects
======================
In languages like Java we have statements that “do” things
in addition to simple computations, like printing values
to screen (``System.out.println`` etc.).
It is possible to use these statements inside a function,
which means the function can compute a value *and* also
perform some effects. Consider for example:
.. code:: java
final float VAT_RATE 21.0; // value added tax
float computeVat(float price)
{
float result = price * VAT_RATE / 100;
System.out.printf("price = %.2f, vat = %.2f\n",
price, result);
return result;
}
void start()
{
float p1 = 320;
float t1 = computeVat(p1);
float p2 = 441;
float t2 = computeVat(p2);
float p3 = 112;
float t3 = computeVat(p3);
System.out.printf("Total VAT: %.2f\n", t1+t2+t3);
}
When run, this program will enter the function ``computeVat`` three times, and every time
the effects inside it will be carried out. So the program prints::
price = 320.00, vat = 67.20
price = 441.00, vat = 92.61
price = 112.00, vat = 23.52
Total VAT: 183.33
With regards to terminology, we say that a function that contains
effect-performing statements is an *effectful function*.
Procedures: “functions” *with* effects, *without* value
=======================================================
Say you have a program where some effect is repeated two or more times. For example:
.. code:: java
Scanner in = new Scanner(System.in);
String n1 = in.next();
System.out.printf("Hi %s!\n", n1);
String n2 = in.next();
System.out.printf("Hi %s!\n", n2);
String n3 = in.next();
System.out.printf("Hi %s!\n", n3);
As usual, as per the DRY rule we should abstract the common pattern in
its own function. We can easily see the common parameter (the Scanner
``in``), and the common effect (``next()`` followed by
``printf()``). However there is no mathematical value being computed,
in other words the mathematical image of the function is not defined!
So what we really want to write looks like this:
.. code:: java
/* nothing */ greet(Scanner in)
{
String name = in.next();
System.out.printf("Hi %s!\n", name);
/* no return */
}
// (... later on ...)
Scanner in = new Scanner(System.in);
greet(in);
greet(in);
greet(in);
This is very well possible, however the syntax for a function
definition is very strict: there must be *something* in the position
before the name of the function.
For this purpose, languages in the C/C++/Java family have a special
keyword: “``void``”. *The ``void`` keyword is used every time there is
a syntax position for a type in the language, but no type makes sense
in that position.*
This is particularly the case for the function above:
.. code:: java
void greet(Scanner in)
{
String name = in.next();
System.out.printf("Hi %s!\n", name);
/* no return */
}
Such a function that performs some effects but does not compute
a result is called a *procedure* in most programming language.
The word “subroutine” is also used in some books but is quite old-fashioned.
Vocabulary
==========
In this lecture we have seen in turn:
- “simple” functions with no effects, that mirror mathematics; these
are called *pure functions*;
- functions that contain some effectful statements, also called
*effectful functions*, further divided in:
- functions that have some effects and also compute a value (no special name), and
- functions that have some effects and do not compute a value, also
called *procedures*, in Java denoted with the keyword “``void``”
instead of a return type.
The terms “pure function”, “effectful function” and “procedure” are
very general and used throughout all programming languages.
Meanwhile, as we have seen before there is another concept looming on
the horizon, that of “objects” as in “object-oriented programming”. If
you remember the `previous lecture`__, Java is part of a family of
languages that provides construct for objects, in particular
classes.
.. __: objintro.html
Classes, in object-oriented programming, can define their own “local
functions” that make a function specific to a group of objects. So on
top of the distinction above, a distinction is often made between:
– “global” functions that are applicable in general, independently from classes; and
– “local” functions within a specific class. These are called *methods*.
For example in Python:
.. code:: python
def sayhi():
# this function is global
print("Hi!")
class Hello:
def sayhi(self):
# this function is local
print("Hi!")
Most language have objet orientation as an optional feature, so a
programmer can use global functions as long as no class is
needed. Unfortunately, Java makes object orientation mandatory, which
means that *all functions in Java are local to a class, ie. all
functions must be methods*.
Because of this specific feature, people using only Java usually confuse
the words “function” and “method”: they would not know any better, because
they never have seen a function that was not also a method! But do not be
intimidated by this conflation, the terms are really distinct and you
would do yourself a favour by remembering the difference.
Any way, the example above really should be placed in their class context,
so we should really have written the following:
.. code:: java
class Hello
{
void greet(Scanner in)
{
String name = in.next();
System.out.printf("Hi %s!\n", name);
}
void start()
{
Scanner in = new Scanner(System.in);
greet(in);
greet(in);
greet(in);
}
// ... a main() function somewhere here ...
}
In this code we have a class named “Hello” that defines two methods,
one procedure called “greet” and another procedure called “start”.
Arguments are passed by value
=============================
There is a peculiarity of a lot of programming languages that tends to
throw off some beginner programmers:
.. code:: java
void foo(int x)
{
int y = x - 3;
System.out.printf("foo %d %d\n", x, y);
x = x + 2;
}
void start()
{
int x = 123;
int y = x - 10;
foo(x);
System.out.printf("start %d %d\n", x, y);
}
What does this program print? Try it out before reading further.
The answer most beginners will propose is the following::
foo 123 120
start 125 120
However, the correct answer is the following::
foo 123 120
start 123 113
What is happening here? The key idea that you need to remember is that
in Java, *the values of parameters that are received by a function
body are copies of the values in the caller function*. Notice the word
“copies”! So no original. This means that the original variable is
left unchanged in the caller function (``start`` in the example)
during the computation of the called function (``foo`` in the
example). Moreover, the variables declared locally in each function
(eg. ``y`` in ``foo``) are just this, “local”, so they are different variables
from the variables with the same name in other functions (eg. ``y`` in
``start``).
This idea is summarized by saying “arguments are passed by value” and
“local variables are not shared between functions”. This is a
characteristing of Java and some other programming languages, and it
does not hold in others. Be sure you pay attention to this feature
when you learn a new language.
Important concepts
==================
- the mathematic concepts around a function, in particular *parameter*, *domain*, *expression*, *image*
- how to transcribe a mathematical function into Java;
- the common mappings of mathematical sets into Java data types;
- the role of “``return``”;
- the difference between a *pure* and non-pure function;
- the difference between a non-pure function and a *procedure*;
- the role of “``void``”;
- the meaning of the word *method*;
- how arguments to functions are passed by value and how to use this fact
when reading/analysing a program.
Further reading
===============
- Introduction to Programming, chapter 4 up to and including 4.3.4 (pp. 135-151)
- Think Java, chapter 6 up to and including 6.3 (pp. 55-60), chapter 3 (pp. 25-38)
----
Copyright and licensing
=======================
Copyright © 2014, Raphael ‘kena’ Poss.
Permission is granted to distribute, reuse and modify this document
according to the terms of the Creative Commons Attribution-ShareAlike
4.0 International License. To view a copy of this license, visit
`http://creativecommons.org/licenses/by-sa/4.0/
`_.