C++ Notes: Function Concepts
Purpose of functions
The purpose of functions is to make the programmer's life easier.
- Write code once, and call it from many places. This insures consistency, and
reduces the cost of writing and debugging.
- A function allows code to be parameterized by passing values to it.
- Functions can be collected in libraries and reused in other programs.
- Functions create new conceptual units
that form the units that programmers use in thinking about a problem.
Naming
For a function to work well as a conceptual unit it has to have a name that
is clear to the human reader.
- Choose a name that has a clear meaning. Eg, "f" is not
a good name.
- Void functions are more readable if a verb name is used
that describes what it does.
Eg, "printAverage" would be a good name for a void function that prints the
average of some numbers. "Average" would not be a good name for it.
- Value-returning functions
- A verb is a good choice for a value returning function that performs
an operation that would naturally be understood to produce a value, eg, "add(x, y)".
A noun which describes the the result can be used. For example,
"remainder(a, b)" would be a good choice for a function that computes the
remainder after division (ie, what the "%" operator does). The noun is a good
choice if you're tempted to add a word like "compute" or "calculate" in front
(eg, "computeRemainder(a, b)").
The "compute" or "calculate" is simple often omitted if the meaning is clear.
- Getter and setter functions. Prefix functions which get a value from an object or data structure
with "get" (eg,
getTime()
). Similarly use "set" for functions that set values
(eg, setTime()
).
- boolean functions should usually start with "is" or another word
that suggests a yes/no answer. Eg, "isOdd(n)" is a good name for a function that returns
true if its parameter is odd, and it's better than simply "odd()".
- Case. There are several conventions, but whichever one you
choose, be consistent to make programs readable. The most common convention is
to start names with lowercase and capitalize the first
letter of each additional word in the name. Some programmers start functions
with uppercase characters, but this is less common.
Cohesion
Each function should do only one thing.
This should be done so that the conceptual unit can be understood easily.
Sometimes it will be convenient
to do two things in a function because you're working on the same data.
Try to resist this temptation. Make two functions if you reasonably can.
Separate I/O and computation. Greater cohesion is almost always
achieved by separating I/O and computation. If possible, put the I/O in
main or in separate functions. If I/O is properly separated, the same
functions which make up a program can be used either in a GUI or command-line
program.
Side-effects
Functions should avoid side-effects such as communicating by means
of global variables. Use of global variables increases
coupling, which makes programs harder to debug and maintain.
Functional Decomposition - top-down programming - successive refinement
The top-down programming style is to write
a short main program that calls on additional functions to
accomplish it task. These functions should similarly
be kept short and call more functions if necessary to
get their task done. Start with the main function, and write
only function stubs which do almost nothing except
maybe print a message that they were called.
Get this running, then expand one of the stubs, get this
running, ... . This very productive style of programming
is related to iterative programming and is one of
the cornerstones of Extreme Programming.
Top-down programming is good for for small programming tasks.
A better approach for larger programs is to divide them into objects.
Size - One page
It is a good idea to keep functions shorter
than one page or one screen. This makes them easy
to comprehend, If you want to make them larger, think about
how you could break the processing into two or more
functions (top-down programming).
Parameters
- Value parameters copy the actual parameter value into
the formal parameter. Changes to the formal parameter, which
is a local variable, do not get passed back to the calling program.
- Reference parameters are implemented by passing the memory address
of the actual parameter to the formal parameter.
Reference parameters are used to pass values back from
a function. This is necessary to return more than one value.
- It is helpful to have a clear idea of the direction of data flow
of each parameter: in means the data only flows into the
function (typically a value parameter), out means the data only flows out of the function
(a reference parameter), or inout means that data flows
both into and out of the function thru this (reference) parameter.
There is no language support for these ideas in C++ altho these
keywords are used in the Ada programming language.
Prototypes
The compiler must know about the return and parameter types before it can
understand the call to a function. You should declare all of your function
prototypes at the beginning of your program. This is one of the primary
purposes of the system include files. If you've written a number of functions
in many files, it is common to define your one include file which defines
the prototypes.