20130115

This week we intruduced the idea of a function.  A function is a self-contained piece of code that we can write once, then use over and over again in our programs.  We started with a very simple example: suppose our program looked like this (where "---" represents some line of code that we don't really care about right now)
    ---
    ---
    print "We've got rocks and trees and trees and rocks"
    
print "We've got rocks and trees and trees and rocks"
    ---
    ---
    ---
    print "We've got rocks and trees and trees and rocks"
   
print "We've got rocks and trees and trees and rocks"
   
print "We've got rocks and trees and trees and rocks"
   
print "We've got rocks and trees and trees and rocks"
    ---
    ---
    ---
    print "We've got rocks and trees and trees and rocks"
   
print "We've got rocks and trees and trees and rocks"
   
print "We've got rocks and trees and trees and rocks"
    ---
    ---

We can save ourselves some typing by defining a function and using it like this:

    def rocks_trees():
       
print "We've got rocks and trees and trees and rocks"
   

    ---
    ---
    rocks_trees()
    rocks_trees()
    ---
    ---
    ---
    rocks_trees()
    rocks_trees()
    rocks_trees()
    rocks_trees()
    ---
    ---
    ---
    rocks_trees()
    rocks_trees()

    rocks_trees()
    ---
    ---

Each time the function is called, it executes as if it were physically inserted in the program at that point.  When the function finishes executing, control returns to the main program at the point where the function was called.

Notice that we can use for loops to tidy this up

    def rocks_trees():
       
print "We've got rocks and trees and trees and rocks"
   

    ---
    ---
    for i in range(2):
        rocks_trees()
    ---
    ---
    ---
    for i in range(4):
        rocks_trees()
    ---
    ---
    ---
    for i in range(3):
        rocks_trees()
    ---
    ---
  

It would be even better if we could move the for loop inside the function.  Well, we can!  Functions can contain any instructions we want.  But we need some way to tell the function how many times we want the loop to execute (twice, then four times, then three times).  We do this with a parameter which lets us pass information to the function and give it a name.  We can redefine our function like this:

    def rocks_trees(n):
        for i in range(n):
       
    print "We've got rocks and trees and trees and rocks"
   

    ---
    ---
    rocks_trees(2)
    ---
    ---
    ---
    rocks_trees(4)
    ---
    ---
    ---
    rocks_trees(3)
    ---
    ---

Notice that in the definition of the function we don't specify that n is an integer, even though it has to be (why?  See what happens if you try rocks_trees(3.9) or rocks_trees("Hello")).  When we get further into our study we will look at  ways to ensure that variables contain the right kind of information before we try to use them.

Functions can call other functions, as in this example:

def function_1(m):
    print "Starting function_1"
    for j in range(m):
        print "blah " ,    # the , forces all output to be on one line until we reach the final "print" without a final ,
    print

def function_2(n):
    print "Starting function_2"
    print n
    for i in range(1,n+1):
        function_1(i)


# main program

function_2(5)

If you run this program you will see that the main program calls function_2 which calls function_1 five times