6.4 Functions

There are many similarities between functions and procedures. We use a function when we are trying to produce a single answer. We have seen a number of predefined Turing functions already. The sqrt function takes a number as a parameter and computes the result of square rooting the number. We say the function returns the square root as a result. Turing insists that we do something constructive with this result. This means that we call functions in a different way from procedures.

If sqrt was a procedure we would call it by simply saying:

sqrt(x)

Since it is a function, however, we would get an error if we tried to call it like that. We need to use the result somehow. Assuming that x is an integer or real variable, here are a number of different ways we could call sqrt:

Now let's take a look at how we can define our own functions. We'll call them the same way as the predefined ones. Let's create a function that finds the largest of three integers. We will also call the function a couple of times to see how it works.

function largest (a, b, c : int) : int
   var big : int
   
   if a > b and a > c then
      big := a
   elsif b > c then
      big := b
   else
      big := c
   end if
   
   result big
end largest 

%main program
put largest(5, 2, 8)
var x : int
x := largest(11, -9, 3)
put x

This program would produce the following output:

8
11

Let us consider the parts of the function. The function heading is similar to a procedure heading with two differences. One is we use the word function instead of procedure. The other is that we need to indicate what kind of a value we are trying to find. We do that by putting a colon and the type after the list of parameters (if there are any). In the body of the function we need at least one result statement. When a function hits a result statement it will return the value after the word result, it will stop executing and return to where the function was called.

In the function largest, we could have avoided the local variable big, by using three result statements. It could be rewritten like this:

function largest (a, b, c : int) : int
   if a > b and a > c then
      result a
   elsif b > c then
      result b
   else
      result c
   end if
end largest  

Although this version is shorter, you need to be careful with this approach. Some would argue that a function should have only one result statement. You definitely want to keep the number of result statements to a minimum, otherwise your function will be too hard to follow.

Here is another example. It is a function that can be used to simulate rolling a single six-sided die.

function roll : int
   var die : int
   
   randint(die, 1, 6)
   result die
end roll 

% main program
put "you rolled a " , roll

We can use local identifiers and global identifiers in functions just like we can with procedures. We can also use arrays as parameters. Here is an example of a function that uses an array as a parameter. It will find the number of positive integers in an array of integers.

function countPositive (a : array 1 .. * of int) : int
   var count : int := 0

   for i : 1 .. upper(a)
      if a(i) > 0 then
         count := count + 1
      end if
   end for
   
   result count
end countPositive

% main program
var numbers : array 1 .. 5 of int := init (50, -2, 40, -9, 99)

put "There were ", countPositive(numbers), " positive numbers in the array." 

It will produce the following output:

There were 3 positive numbers in the array.

Exercise 6.4

  1. Study the following function definition and then answer the questions that follow it.
    function mystery (a, b : real) : int
       if a < b then
          result -1
       elsif a = b then
          result 0
       else
          result 1
       end if
    end mystery
    
    1. What is the identifier of the function?
    2. What are its parameters?
    3. What type of value does the function compute?
    4. What part of the definition forms the function heading?
    5. What does the function do?
  2. The function definitions shown below lack both punctuation and indentation. Rewrite the definitions correcting these defects and state, in a few words, the purpose of each function.
    1. function first (a b char) char if a < b then
      result a else result b end if end first 
    2. function even (value int) boolean var temp
      boolean := false if value mod 2 = 0 then temp := true end
      if result temp end even 
  3. Study the following program and then answer the questions that follow it.
    var height, width, difference : int
    
    function posDiff (first, second : int) : int
       if first > second then
          result first - second
       else
          result second - first
       end if
    end posDiff
    
    put "Please enter the height"
    get height
    put "Please enter the width"
    get width
    put "The height is ", height, " and the width is ", width
    put "They differ by: ", posDiff(height, width) 
    1. Identify any parameters.
    2. Identify any arguments.
    3. What type of value does posDiff return?
    4. What output would the program produce given input of 12 and 8?
    5. What would happen if the words height and width were reversed in the last put statement?
    6. Rewrite posDiff, this time using the predefined function abs in the definition.
  4. State which of the following fragments are invalid, giving reasons for your answers.
    1. put abs(-7) 
    2. var x : int := abs(-7) 
    3. var x : int := put abs(-7) 
    4. var x : int := -7
      abs(x)
      put x 
  5. The function ceiling computes the smallest integer that is not less than a given real value (if the real value is not negative) and it computes the largest integer that is not greater than the given real value (if the real value is negative).
    1. Write a function definition for this function.
    2. Test your definition in a program that reads real values and prints a table showing the numbers and the value of the ceiling function of those values. Test your program with the following values:
      3.1   25.9   67.0   0.0   -1.1   -67.5   -15.9
  6. Complete a function that has a heading of
    function meanValue(a : array 1 .. * of int) : real 
    The function should return the arithmetic mean (the average) of the values in the array.
  7. Write a function smallest that is to have as a parameter an array of real values. The function is to return the value of the smallest element in the array.
    1. Write a definition for a function that has a single integer parameter number. The function should return the number of digits in number.
    2. Test your definition in a program that reads integers and prints a table showing the numbers and the number of digits in each one. Test your program with the following values:
      4000   -23   -7   0   5   -12345