I heavily documented the code so that beginners might be able to make sense of what’s going on. If you have any questions, please leave a comment!

/*

* Name: fibonacci.go

* Date: November 16, 2009

* Author: Jack Slingerland (jack.slingerland@gmail.com)

*

* Description: This program is a Fibonacci number calculator.

* It may be invoked as follows: “./8.out [goal]”, where [goal]

* is the Fibonacci number that you want to computer. Currently

* the program is limited to the 46th Fibonacci number due to

* overflow, however a new implementation is in the works that

* won’t have that limitation. The real purpose of this program

* is to show how Go-routines work, and how communication and

* sychronization between them is handled using channels.

*/

package main

import (

“os”;

“fmt”;

“strconv”;

)

/*

* This ADT holds all the information needed to calculate the next

* Fibonacci number in the sequence. Current is the current index

* in the series (ex, 5 = We’re on the 5th number in the sequence).

* Goal is of course, the number in the sequence that we’d like to

* achieve.

*/

type fibonacci struct {

a int;

b int;

current int;

goal int;

}

func main() {

//Check the command line arguments for sanity.

goal, err := checkArgs();

if(err != “”) {

fmt.Fprintf(os.Stdout, “Error: %s”, err);

os.Exit(1);

}

//Special case: If the goal is 2 or less, the Fibonacci number is always

//1. This isn’t really worth creating channels + go routines for.

if(goal <= 2) {

fmt.Fprintf(os.Stdout, “Fibnonacci Value %d is: %d\n”, goal, 1);

} else {

//Construct two channels, the input channel acts as our communication

//between the Go routines. As you can see, it can be typed as an

//ADT(struct), which makes passing data REALLY easy between go routines.

//The final channel is for passing back the goal Fibonacci number to

//the main thread.

input := make(chan fibonacci);

final := make(chan int);

//Create a new fibonacci object and set it’s values.

var x fibonacci;

x.a = 1;

x.b = 1;

x.current = 2;

x.goal = goal;

//Create a new Go routine with the addNumber function. We pass it the

//two channels that were declared earlier. This is similiar to “spawn”

//in Limbo.

go addNumber(input, final);

//The first addNumber() Go routine will block until it gets input from

//the input channel. So, we pass it our fibonacci object.

input <- x;

//Now, we block and wait for the Go routines (addNumber()) to finish up

//and send us back the final value.

number := <- final;

//Print the value out and we’re done!

fmt.Fprintf(os.Stdout, “Fibnonacci Value %d is: %d\n”, x.goal, number);

}

}

/*

* The addNumber() function takes two channels as parameters. One is a

* channel of fibonacci, which holds information about which number to

* calculate and when to stop, and then a channel of type int, which will

* be used to send the final goal number back to the main thread.

*/

func addNumber(input chan fibonacci, final chan int) () {

//Block here and wait for input from the previous thread

//or the main thread, depending on the situation.

x := <- input;

//Here we check to see if we have met our goal, if we

//have, we return the goal value back to the main thread

//via the final channel. Otherwise, we calculate the

//next number in the sequence.

if(x.current < x.goal) {

fib := x.a + x.b;

//This is fun because you can assign multiple values at once.

//x.a <- x.b and x.b <- fib. 🙂

x.a, x.b = x.b, fib;

x.current = x.current + 1;

//Make a new channel of type fibonacci so that we can communicate

//with the new Go routine that we are about to create.

output := make(chan fibonacci);

//Pass the new Go routine the newly created channel, as well as the

//final channel that was passed in from the caller.

go addNumber(output, final);

//Send the fibonacci object out on the channel.

output <- x;

} else {

//Send the goal value out on the channel back to main.

final <- x.b;

}

//Go routine dies now.

}

/*

* The checkArgs() function is a great example of returning multiple

* values. We return an integer and a string to the caller, so handling

* errors is fairly straight forward.

*/

func checkArgs() (int, string) {

//Fetch the command line arguments.

args := os.Args;

//Check the length of the arugments, return failure if that are too

//long or too short.

if((len(args) < 2) || (len(args) >= 3)) {

return -1, “Invalid number of arguments.\n”;

}

//Convert the goal argument to an integer.

goal, err := strconv.Atoi(args[1]);

//Make sure the conversion went correctly, otherwise return failure.

if(err != nil) {

return -1, “Invalid argument. Argument must be an integer.\n”;

}

//Since this implementation is limited, make sure the user can’t go

//beyond the program’s limits.

if(goal > 46) {

return -1, “This program only calculates up to the 46th Fibonacci number.\n”;

}

//Check the lower bound as well.

if(goal < 1) {

return -1, “Invalid range. Number must be >= 1.\n”;

}

//On success, return the goal value and an empty string indicating

//that everything is good.

return goal, “”;

}