Algorithms : Functions

Algorithms : Functions

Break it down!

Introduction

Flowchart functionsIn this section of the algorithms tutorial we will look at functions. Think of a function as a means to break down a bigger algorithm into a series of smaller sub algortihms.

When you get to bigger, more complex problems, utilising functions has several advantages :

  • Solving a series of smaller problems is easier than trying to solve one big problem.
  • Functions may be called multiple times, removing the need for duplicated code.
  • Readability of the overall logic becomes easier.

In this section we will use mostly pseudocode to illustrate the concepts. We will illustrate how to implement the ideas in flowchart as well.

Functions

There are two parts to utulising a function. The first part is the function definition. This is where we include the code that makes up the function :

BEGIN functionName ( var1, var2 )
  # Code goes here.
  Return var
END functionName

Then we have the second part which is the function call. This is where we call the code that makes up the function :

myVar = functionName ( var3, var4 )

flowchart function layout

First off we will illustrate with a simple example that doesn't use parameters or a return value. Then we will expand the functionality, adding these back in.

Get User Input

  1. BEGIN
  2.   Display "Welcome"
  3.   getUserInput()
  4.   Display "Now just one more question"
  5.   getUserInput()
  6. END
  7.  
  8. BEGIN getUserInput ()
  9.   Display "We just need some more input"
  10.   Get userInput
  11.   Display "Thank you for that information"
  12. END getUserInput

The above algorithm doesn't really do anything useful. It is really just to illustrate how a function is set up and also that a function may be called just once or as many times as you like.

Parameters

A function becomes a lot more useful when we make use of parameters. Parameters are a way to pass values into the function.

This algorithm will ask for a width then print out a triangle of asterisks of that width.

Print Triangle

  1. BEGIN
  2.   Get width
  3.   Set counter to 0
  4.   WHILE counter < width
  5.     printLine(counter)
  6.     Increment counter by 1
  7.   ENDWHILE
  8. END
  9.  
  10. BEGIN printLine (length)
  11.   Display length number of "*"
  12. END printLine

The name of the parameter when the function is called does not have to be the same name as the name of the paramter in the function definition. They will match up with the order of how they are listed. This allows us to call the function from multiple locations, passing in different data each time.

Return Values

A function becomes even more useful when it can send back the results of its processing. This is achieved via a Return value (or values).

In the following example there are two functions, one to calculate the perimeter of a square and the other to calculate the area.

Calculate Square Details

  1. BEGIN
  2.   Get width
  3.   WHILE width > 0
  4.     perimeter = calculate_perimeter(width)
  5.     Display permimeter
  6.     area = calculate_area(width)
  7.     Display area
  8.     Get width
  9.   ENDWHILE
  10. END
  11.  
  12. BEGIN calculate_perimeter (length)
  13.   perimeter = length * 4
  14.   Return perimeter
  15. END calculate_perimeter
  16.  
  17. BEGIN calculate_area (length)
  18.   area = length * length
  19.   Return area
  20. END calculate_area

It is possible to combine the calculation and return lines for simple functions like these eg. "Return length * 4" combining lines 13 and 14. Generally it's better to use the approach used above however as it helps to make it more readable.

Recursion

Recursion is an interesting pattern in algorithms where a function calls itself as part of its processing. Effectively, we are solving a problem by repeatedly breaking the problem down into smaller versions of itself that branch off the earlier versions. It is a very powerful problem solving method however it can be a bit hard to get your head around at first. It is also only useful for a small subset of problems.

Let's say we want to find the Factorial of a number (that is X * (X-1) * (X - 2) ... 2)

Calculate Factorial

  1. BEGIN
  2.   Get initialNumber
  3.   result = calculte_factorial(initialNumber)
  4.   Display result
  5. END
  6.  
  7. BEGIN calculate_factorial (number)
  8.   IF number == 2 THEN
  9.     result = 2
  10.   ELSE
  11.     result = number * calculate_factorial(number - 1)
  12.   ENDIF
  13.   Return result
  14. END calculate_factorial

A recursive function must always contain a decsion which allows to break out of calling itself. Otherwise the processing would run indefinitely with no means of terminating.

An alternate approach

An alternate approach to managing return values is to set the return value (or return values) to be the last items in the parameter list.

Calculate Square Details alternate

  1. BEGIN
  2.   Get width
  3.   WHILE width > 0
  4.     calculate_perimeter(width, perimeter)
  5.     Display permimeter
  6.     calculate_area(width, area)
  7.     Display area
  8.     Get width
  9.   ENDWHILE
  10. END
  11.  
  12. BEGIN calculate_perimeter (length, perimeter)
  13.   perimeter = length * 4
  14. END calculate_perimeter
  15.  
  16. BEGIN calculate_area (length, area)
  17.   area = length * length
  18. END calculate_area

It is generally recommended that you do not use this approach however as it can be ambiguous as to which parameters are being passed in and which are return values. When writing your algorithms you should always aim for clarity and this method does not help in that regard. It is illustrated here only so that if you see it written elsewhere (in an exam for example) you will understand what is going on.

Here is the example flowchart from up above reformatted in this alternate approach.

flowchart function layout in an alternate way

Theory

Writing functions in your algorithms is easy. Using them to their best effect is somewhat of an art and will take some time to master.

Here are some ideas that will help you on your way to mastery.

A clean and uncluttered main function

When used well, functions can help to create a clean and uncluttered main function (sometimes referred to as a mainline). A function that acts to guide other functions that do the work and make the overall logic of the program even easier to understand. For example, this could be the main function for a simple game :

Calculate Square Details (poor use of functions)

  1. BEGIN
  2.   settings = load_settings()
  3.   play_intro()
  4.   game = setup_game(settings)
  5.   result = play_game(game)
  6.   save_score(result)
  7.   display_leaderboard()
  8.   show_credits()
  9. END

Generic and Reuseable

When you create functions you should aim to make them generic and reuseable. This will allow your functions to be incorporated across more areas of processing and also to be easily reused across programs (saving you time in the long run). Once the algorithms are proven to work reliabley you will be able to drop them into future work confidently and not need to waste time retesting the logic.

There are several things you can do to help make your functions more reuseable :

  • Make sure inputs are passed in as parameters as opposed to via input statements.
  • Return results of processing rather than Displaying them.
  • Use generic names for variables to help remove the assumption that the function may only be used for a specific task.
  • Where possible, use calculations rather than hard coding values so that any input can easily be managed.

One Function, One Task

Ideally, a function should perform one task and one task only. This greatly helps with reuseability and readability. For example in the code above we could have combined calculating the area and perimeter into one function as follows :

Calculate Square Details (poor use of functions)

  1. BEGIN
  2.   Get width
  3.   WHILE width > 0
  4.     perimeter, area = calculate_details(width)
  5.     Display permimeter
  6.     Display area
  7.     Get width
  8.   ENDWHILE
  9. END
  10.  
  11. BEGIN calculate_details (length)
  12.   perimeter = length * 4
  13.   area = length * length
  14.   Return perimeter, area
  15. END calculate_perimeter

Initially this may seem better as we have written less lines of code however this function is now less generic and less reuseable. The function performs two tasks and later on if we only needed the area, for instance, it would be ineffective. The name of the function is now also less descriptive than the two separate functions were previously and so the code also doesn't read as elegantly.

Even though it may seem like more work (and lines of code) in the short term, breaking down the processing into several smaller functions that only do one specific bit of processing will save you time in the long run and make for easier expansion of your processing when you want to add functionality.

Summary

Functions
Useful to break processing into smaller chunks.
Parameters
In brackets after the function definition and are passed down into the function.
Return values
Pass the result of the processing back to the initial calling code.

Recursion.
A function that calls itself to iterate on processing a smaller version of the same processing.