Saturday, April 23, 2011

Cross Compiling Google Go Code

This is more of a note to self, so I can look up this information in the future as needed. Google Go makes it really easy to cross-compile. Here is how you an compile your Go project for another architecture. The first step is to compile the cross compiling compilers (I can't believe I just typed that). So lets checkout the source code for the go compiler.
hg clone -r release https://go.googlecode.com/hg/ go

Now to compile the Go compiler for the architecture of your machine, simply cd into the go/src directory and run the all.bash script
cd go/src; ./all.bash
If you want to create compilers for a different architecture you set the GOARCH environment variable and then run the make.bash script.
GOARCH=arm ./make.bash
GOARCH=386 ./make.bash
GOARCH=amd64 ./make.bash

The all.bash script compiles the compiler and runs the unit tests, the make.bash script just compiles the compilers.

This will create separate compilers, linkers and assemblers for each of the three architectures. Because each compiler, linker and assembler have a different name you can have support all architectures simultaneously.

Once you have the Go compilers compiled you can now compile your project for different architectures by creating a Go Makefile and setting the GOARCH environment variable before typing make.

GOARCH=arm make
GOARCH=386 make
GOARCH=amd64 make

That's it! You can now cross compile your Go code. More information on the Go compilers, creating a Go Makefile and getting started with Go can be found here, here, and here respectively. Happy Hacking!

Friday, April 22, 2011

I'm back

Last year I decided that it was time to finish up my Masters degree. I recognized that in order to finish in a timely manner I would need to forgo all hobbies for a while and so this blog has been on hold. I'm now done, or at least I'm at the stage where I'm waiting for the final announcement that I'm done and so I'm now returning to normal life. After having dropped out more than a year ago I'm finding that it's taking some time to get adjusted to normal non-academic life. I'm also slowly starting to remember all the non-homework activities that I used to participate in. I wonder how long it will be before I become as busy as I was before.

Tuesday, March 16, 2010

Developer Etiquette

I created a list of etiquette guidelines for Software Engineers.  These etiquette guidelines are not for social interactions, but are instead for writing code.  Like most etiquette guidelines these are designed to minimize the discomfort for others.  So here they are.

Before committing I will:

  1. Review the patch.
  2. Review the list of files that are not being committed, but have been modified or are new.
  3. Compile the code.
  4. Run any affected unit-tests.
  5. Test the code to make sure it does not break core functionality.
The reason behind #1 is simple.  It's very easy to accidentally commit code that's not ready, or that contains printf debug code.  It's quite obnoxious to have your terminal sprayed with hundreds of "XXX Hey I'm executing function foo()."  By following guideline number #1 you will rarely accidentally commit half-baked code.  The git add --patch command makes this really easy.

Guideline #2 saves you from forgetting to commit some critical patch, or more commonly forgetting to add a new file to the repository.  I've found that most of the time when code compiles on the developer's computer but not anyone else's, it's because they forgot to add a file.  The git status command helps here.

Guideline #3 is simple.  Committing code that doesn't compile turns a O(1) problem into a O(n) where n is the number of developers on your team.  Don't ever check in code that doesn't compile.

Guideline #4 ensures that you don't accidentally break the unit-tests.  It is much easier to fix bugs earlier rather than later.  So if you break the tests it's better to find out before you commit.

Guideline #5 is similar to #4 but assumes that not all of your code is covered by unit-tests.  Even if you test every line of code with unit-tests, your unit-tests won't tell you that you just made your GUI look like puke.  So run the code and make sure nothing broke.

If you follow these guidelines you can still write horribly broken code and be a terrible developer, but at least you won't prevent your co-workers from being competent.

Wednesday, January 20, 2010

Easy to Use

I've noticed that when choosing a tool for software development one of the criteria that's often proposed is the tool should be "easy to use". While I agree that ease of use should be a criteria for choosing a tool I've come to realize that I have a different opinion on what "easy to use" means than others. When I say a tool is "easy to use" I mean it literally. A tool that is easy to use should make it really easy for me to do what I want. Here are some of the development tools that I use that I consider easy to use:

  1. vim
  2. git
  3. The command line (bash)
All three of these tools let me do my job as quickly and painlessly as possible.  If you asked others for a list of similar tools that are easy to use you may get the following:

  1. notepad
  2. svn
  3. GUI's
By my definition the above tools are not easier to use than my list (they don't allow me to do my job as quickly or painlessly) but they are easier to learn.  I'm not sure if easy to learn and easy to use must be mutually exclusive but I can't think of any tools that I use frequently that have both qualities.  There is nothing wrong with choosing a tool that's easier to learn over one that's easier to use as long as you use the tool infrequently.  Investing years to fully learn vim is a waste of time if you only edit text files for a few minutes every month.  If your going to use a tool frequently over a long period of time then you should spend the time to learn the tool that's easy to use even if it isn't easy to learn.

Tuesday, January 5, 2010

Recursion and Inductive Proofs

I've discovered that programmers frequently stumble when writing recursive algorithms. There are some simple rules that programmers can steal from mathematics to make writing recursive algorithms easy. I should point out that I'm only talking about writing recursive algorithms for interacting with recursive data-structures (lists, trees, etc.). Let's get started by reviewing some basic steps for proving a statement holds for all natural numbers n using an inductive proof.
  1. Base case:  Show the statement holds for a value of n (usually n=1 or n=0).
  2. Inductive step:  Assuming the statement holds for any value of n then show it also holds for a value of n+1
Rule 2.5 would be to make sure that the inductive step reduces the problem space.  Using a base case of n=0 and then and inductive step of n-1 wouldn't be a valid proof because the inductive step does not really reduce the problem space (remember we're talking about natural numbers for this example).  So let's use an inductive proof to show that 0+1+2...n=(n(n+1))/2.

Base case: Show the statement holds for n=0
0=0(0+1)/2
This equation clearly holds.

Inductive step:  Assuming the statement holds for any value of n then show it will also hold for n+1.
0+1+2...n+(n+1) = ((n+1)((n+1)+1)/2
If we assume that the statement holds for n then we can reduce the expression.
(n(n+1))/2 + (n+1) = ((n+1)((n+1)+1)/2
Using some basic algebra we can reduce both sides and discover that the inductive step holds.

Now we can apply same (perhaps slightly tweaked) rules to writing a recursive algorithm for finding the length of a linked-list (a recursive data-structure).

Let's start out with the function signature.
int length(Node *node)
{
  // Do stuff here
}
Base case: Write the algorithm for n=0 (the linked-list with 0 nodes).
int length(Node *node)
{
  if (NULL == node)
  {
    return 0;
  }
  // Do more stuff here
}
Congratulations! If you've make it this far you're above average. You've solved the base case without dumping core.

Now onto the inductive step: Assume that your length function will work for lists of length n now write code to make it work for lists of length n + 1.
int length(Node *node)
{
  if (NULL == node)
  {
    return 0;
  }
  else
  {
    return 1 + length(node->next);
  }
}
Notice that if we assume that "length(...)" works for lists of length n then for lists of length n + 1 all we need to do is add 1 to the length. You should also notice that we passed node->next to the "length(...)" function not just node because rule 2.5 states that the inductive step must reduce the problem space and just passing node would not reduce the problem space. Congratulations! If you've make it this far you're now well above average. Now not only will your algorithm not core dump, but it won't hang either.

So let's review what we've done. We've used the rules for inductive proofs to guide us in writing a recursive algorithm. Does this mean we've proved that this algorithm is correct? The answer is, not really or at least, not formally. Even though we haven't proved this algorithm is correct we can be much more confident that it will work.

If we were to write unit-tests for this algorithm (which you should *always* do before writing the algorithm) we could use the rules of induction to guide our unit tests. We could write a test for testing the base case and another test for testing the inductive case.

Since math has been around longer than computers, it makes sense that we could borrow a few ideas from it to make our jobs easier.

Friday, November 27, 2009

Google's Go trying to be too clever.

I've discovered a couple of cases where Google's Go is trying to be too clever. There are two expressions who's behavior changes based upon what is done with evaluated results. Lets look at a bit of code.

package main

import . "fmt"

// Define a simple struct
type foo struct {
        a int;
}

// Define an interface
type plus1 interface {
        add1() int;
}

func any(a interface{}) {
        v := a.(plus1).add1();
        Printf("%v\n", v);
}

func main() {
        f := foo{1};
        any(f);
}

So this code defines a simple struct "foo" with a single member a. It defines a "plus1" interface that says that any struct that implements the interface must implement an add1 method that returns an int. The main function instantiates a "foo" and passes it onto the any function. Because "foo" doesn't implement the "plus1" interface the first expression in the function "any" will fail with a runtime exception. the "a.(plus1)" is called a type assertion and it fails if the "a" doesn't implement the "plus1" interface. Now we can switch this code so the type assertion won't assert by assigning the results of the type expression to some variables. Consider the following:

package main

import . "fmt"

// Define a simple struct
type foo struct {
        a int;
}

// Define an interface
type plus1 interface {
        add1() int;
}

func any(a interface{}) {
        a1, ok := a.(plus1);
        if ok {
                v := a1.add1();
                Printf("%v\n", v);
        }
 }

func main() {
        f := foo{1};
        any(f);
}

The only difference in this code is that the type assertion will not assert but instead return two values (yes Go can return multiple values!). The second value is of type bool which indicates whether the first value is "a" cast to "plus1". If "a" isn't of type "plus1" then instead of asserting the type assertion will just return false for the second parameter. While this is clever, it feels like assigning the return value to a variable magically alters the behavior of the expression. I think this will just make the language too difficult to learn. The second operation has to do with go-routines and I'll talk about it next time.

Wednesday, November 18, 2009

Letting the compiler find the bugs

Lets start by looking at a bit of contrived C/C++ code. See if you can spot the (hopefully obvious) bug.
#include <stdio.h>

int main()
{
    float fieldLength = 120; // yards
    float fieldWidth  = 48.77; // meters
    float yardsInAMile = 1760; // yards per mile

    printf("You must run around the perimeter of an American football field %f times to run a marathon\n", 
            26.2 * (yardsInAMile / ((fieldLength * 2) + (fieldWidth * 2))));

    return 0;
}

It probably shouldn't take you too long to realize that in the above code I'm mixing units. I'm adding yards to meters. While bugs like this are obvious in trivial code they can be difficult to track down in more complex software. What can we do to prevent bugs like this from creeping into code? One solution is to use coding standards to reduce ambiguity. For example you could decide to use metric units for all data in your project. You could also use 'typedefs' and variable naming conventions to make errors even more obvious. Consider the following:

#include <stdio.h>
typedef float yards;
typedef float meters;

int main()
{
    yards fieldLengthYards = 120; // yards
    meters fieldWidthMeters  = 48.77; // meters
    float yardsInAMile = 1760; // yards per mile

    printf("You must run around the perimeter of an American football field %f times to run a marathon\n", 
            26.2 * (yardsInAMile / ((fieldLengthYards * 2) + (fieldWidthMeters * 2))));

    return 0;
}

By including the units in the variable names and types it makes the programmers intentions clear. It's also easier to spot bugs in code audits. For even more safety you could define Meters and Yards classes that encapsulate the floats and prevent mixing of types. The advantage of defining new types/classes is the compiler can now ensure that you don't mix types. The disadvantage is that you'll end up writing a class for each type, with lots of overloaded operators. Writing a class for every unit feels to burdensome for all but the most critical code (nukes, airplane firmware, surgery robots, etc.). The problem with the above 'typedef' solution is that C/C++'s 'typedef' really only defines an alias for the type. Both the type-checker and the compiler will treat 'meters' the exact same way it treats 'yards', we want the type-checker to treat 'meters' and 'yards' as distinct types and the compiler to treat them both as floats. Google's new system language Go lets you do just that. Lets reproduce the original bug in Google Go.

package main

import "fmt"

func main() {
    var fieldLength float = 120; // yards
    var fieldWidth  float = 48.77; // meters
    var yardsInAMile float = 1760; // yards per mile

    fmt.Printf("You must run around the perimeter of an American football field %f times to run a marathon\n", 
            26.2 * (yardsInAMile / ((fieldLength * 2) + (fieldWidth * 2))));
}

This has the same bug as the C/C++ code above. The code should be readable to a C/C++ developer, the only really "weird" thing is that the type follows the variable name. Now let's use Go's strong typing to let the compiler catch the bug for us.

package main

import "fmt"

type yards float
type meters float

func main() {
        var fieldLength yards = 120;
        var fieldWidth meters = 48.77;
        var yardsInAMile float = 1760; // yards per mile

        fmt.Printf("You must run around the perimeter of an American football field %f times to run a marathon\n",
                26.2*(yardsInAMile/((fieldLength*2)+(fieldWidth*2))));
}

Notice that all we did is define two new types 'yards' and 'meters' all which should act like 'floats', but should be treated differently by the type-checker. When we compile we get the following error:
invalid operation: fieldLength * 2 + fieldWidth * 2 (type yards + meters)

The most important part of the error is at the end where it tells us we're trying to add 'yards' with 'meters'. The type checker found the bug for us! So how do we fix it? We need some conversion routines. So lets add some methods to the types and fix the bugs.

package main

import "fmt"

type yards float
type meters float
type miles float

func (m meters) toYards() yards { return yards(m * 1.0936133) }
func (y yards) toMiles() miles  { return miles(1760.0 / y) }

func main() {
        var fieldLength yards = 120;
        var fieldWidth meters = 48.77;

        fmt.Printf("You must run around the perimeter of an American football field %f times to run a marathon\n",
                26.2*((fieldLength*2)+(fieldWidth.toYards()*2)).toMiles());
}

With the corrected program we see that you only have to run around the field 133 times instead of 136.6 times!

Go isn't the first nor the only programming language that allows you to encode units as types, but it's close enough to C/C++ for a good comparison. So what's the runtime overhead of the change? Well there are a couple of method calls (toYards(), toMiles()) where the original version did the conversions inline. The error checking happens at compile time because Go is statically typed so there's no runtime performance hit. Personally I'd much rather wait for my program to call a couple of functions than to run around an American football field 3.6 more times.

By carefully using Go's (or any other language with a good type system) type system you can spend more time writing code and less time tracking down bugs.