Functions

Abstraction

The Abstraction Principle states:

A client should be able to use a function without knowing how it's implemented. Conversely, a provider should be able to modify the implementation of a function without worrying about breaking client code.

A language supports the Abstraction Principle by allowing programmers to separate the description of a computation (implementation) from its execution (use).

In effect, when a programmer declares a function or procedure:

def square(x: Int) = x * x

she's describing a computation:

x * x

However, the computation isn't executed at this point. That happens later when the function is called:

square(2 + 3); // = 25
square(2 * 2); // = 16

Note that the function can be called many times, even though it only needs to be described once.

Procedures versus Functions

A function returns a useful value, while a procedure causes a side effect such as updating a variable or printing something.

In the example below getCount is a function while incCount and printCount are procedures:

class Counter {
  private int count = 0;
  public int getCount() { return count; }
  public void incCount() { count = count + 1; }
  public void printCount() { System.out.println("count = " + count); }
}

In Java (and other languages) procedures usually have a return type of void. (Scala uses Unit.)

A hybrid function returns a useful value and causes a side effect:

int getCount() {
  System.out.println("count = " + count);
  return count;
}

Hybrids should be avoided because their side effects can be unwanted. For example, they can interfere with user interfaces.