**[work in progress](<../work%20in%20progress.md>)**

Functions are a very core component of effective programming, and it is unfortunate that the nature of the current curriculumn does not place them front and centre.

In mathematics, a function is a "projection" - it projects things from one value to another. For example, squaring a number is a function. You may have come accross them in your maths lessons (if you haven't yet, you will as part of GCSE maths). In maths these are often written as f(x) = <some expression> - for example f(x) = x * 2 or f(x) = x + 1 or f(x) = 33 * x + 23 * x**2.

A function maps "input" values to "output" values. For example, f(x) = 2 * x would map 2 to 4 or 6 to 12 or 32 to 64. The function f(x) = x ** 2 would map 1 to 1, 2 to 4, 3 to 9, 4 to 16, and so on.

We can define the function f(x) = x ** 2 in Python as follows:

def f(x):
	return x ** 2

And "call" a function (that is, we provide a specific value of x to the function, and compute the answer). Suppose we set x=3. Then we run the function. On the first line, we need to calculate x ** 2. We know that x=3, so Python uses simple assembly maths to evaluate 3 ** 2 = 9.

The reason that we have to "call" functions is because a function is a template. Think about a cookie cutter - when you hold the cookie cutter in your hand it doesn't do anything. However, when you "call" the cookie cutter (i.e. you use it to cut out a cookie from the mixture) you provide a specific input (the cookie mixture) to the function, and you obtain a specific output (i.e. the correctly-shaped cookie). Even if you define a function (the cookie cutter) the function won't do anything until you call it (start cutting actual cookies from the dough).

Note that x is called a "dummy variable" - that is, the fact that the variable is called x is not important. We could equally well have called it y, and written the following function:

def f(y):
	return y ** 2

Or we could have called it z and written:

def f(z):
	return z ** 2

The next thing to take note of is that variables declared inside a function are only visible inside that function.

So this program would error:

def f(x):
	z = 32
	return z ** x
print(z)

With a message like z is not defined. However this function would indeed print "32" to the terminal.

def f(x):
	z = 32
	print(z)
	
f(x)