Dan Worth How hard could it be?

How I do Dynamic Type Loading in Go

In Java and Python it's common to inspect your execution environment and instantiate a different Class or Module. In Java you can use Class.forName(String className) and if className does not exist the function will throw a ClassNotFoundException. It's up to the developer to deal with the exception. Python has the magical __import__ builtin which does a very similar thing.

Ok, so I've come to love this technique in Java and Python but how do I do something like this in Go. Go has a reflect package that allows you to inspect types at runtime. That is cool and all but how do I load a specific type at runtime. This isn't possible in the same manner as Java or Python. At first I was devastated then I started to look into how the database/sql package worked with respect to using different drivers based on a connection string. I found some neat code in the database/sql package. Take a look at the snip it below:

var drivers = make(map[string]driver.Driver)

// Register makes a database driver available by the provided name.
// If Register is called twice with the same name or if driver is nil,
// it panics.
func Register(name string, driver driver.Driver) {
        if driver == nil {
                panic("sql: Register driver is nil")
        }
        if _, dup := drivers[name]; dup {
                panic("sql: Register called twice for driver " + name)
        }
        drivers[name] = driver
}

So, first an unexported map of type string and driver.Driver is created. The Register function is used to register a specific name (key in the map) with a struct that implements driver.Driver and panics if the user tries to register the name more than once or driver is nil.

We've looked at how we can register our stucts with a name but how do we use them? Let's take a look at the implementation of func Open in database/sql:

func Open(driverName, dataSourceName string) (*DB, error) {
        driveri, ok := drivers[driverName]
        if !ok {
                return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
        }
        db := &DB{
                driver:   driveri,
                dsn:      dataSourceName,
                openerCh: make(chan struct{}, connectionRequestQueueSize),
                lastPut:  make(map[*driverConn]string),
        }
        db.freeConn = list.New()
        db.connRequests = list.New()
        go db.connectionOpener()
        return db, nil
}

Open takes a driverName (our key to the drivers map) and a dataSourceName or DSN. The driver is pulled out of the map and verifies it was registered. The rest of the function is out of scope for this post but you see how the driver is then passed on to other structs that will use the database driver.

Why is this cool? Well, now a database driver libraries can Register their structs that implement the driver.Driver interface. Hmm... Wait, so when I use the MySql driver in Go I don't need to call the Register funcion in the database/sql package I just use the Open function in the database/sql and off I go... What are you talking about.

So, when you have an import like the following

import (
    _ "github.com/bradfitz/mysql"
)

That import will register the MySql driver with database/sql package via an init() function. Take a peek at. Pretty cool right.

So, to sum it all up... Go doesn't really allow you to do dynamic type loading in the langauge but you don't really need the language to do this for you. If you leverage interfaces and you should you can take advantage of the technique used by database/sql. This should solve the problem for you 90% of the time.

func init()

Go has an initialization function that can live in package scope or file scope. You can have multiple init() functions in the same package or file scope. As far as I know this is the only function or variable that can exist in the same file scope. See the following code as a demistration of what I'm talking about:

package main

import (
  "fmt"
)

func init() {
    fmt.Println("This is init 1")
}

func init() {
    fmt.Println("This is init 2")
}

func init() {
    fmt.Println("This is init 3")
}

func main() {
    fmt.Println("Hello init()") 
}

Code on play.golang.org

In the code above I have three different init() functions according to the spec

Package initialization—variable initialization and the invocation of init functions—happens in a single goroutine, sequentially, one package at a time. An init function may launch other goroutines, which can run concurrently with the initialization code. However, initialization always sequences the init functions: it will not start the next init until the previous one has returned.

What this means to me is that the init functions will be executed in sequential order based on package imports. The spec also states:

Multiple such functions may be defined, even within a single source file; they execute in unspecified order.

So the order init() is called within a package or file is unspecified.

When I first came across a sample code that had multiple init() functions in a single file I thought for sure it was going to be a compile time error. Nope! This is defined in the spec under Program execution section of Program initialization and execution.

I still think this is very strange and leads to code smell but The More You Know the better IMO.

2014 Goals

I've set some pretty aggressive goals for myself in 2014. I'm writing them down in an attempt to make sure I keep myself accountable for each of these goals. My goals are listed below which I'll go into a little more detail about each and my rationale behind each one.

  • Complete a Sprint Triathlon
  • Working version of an Open Source XMPP Server
  • Write atleast two blog posts per month

Complete a Sprint Triathlon

Triathlon!?!? Yes, well a Sprint Triathlon which is about half of a normal Triathlon. I've chosen to complete a sprint triathlon because it's a concrete goal. Instead of trying to "lose weight" I'm signing myself up for an event where a side effect will be to lose weight and get in better shape. The Sprint Triathlon I'm going to participate in is to Swim 1/4 Mile, Bike 10 Miles, and Run 3.1 Miles. When I look at those numbers it doesn't seem that difficult but I currently can't even run on the treadmil for a continuous 5 minutes. It's a good thing I have until July 19th to train. I'm going to need all the time I can get.

Working version of an XMPP Server

I started a project with the GoLang Philly group. We have a project name which is Fireside and a repo on github. That is pretty much as far as the project has gone. In 2014 I would like to turn this project into a real working XMPP Server. As I build out the project I'm going to be writing about the progress of the project and different parts of the development process. This project will be a large source of content for this site in 2014.

If you feel like helping out visit the project on GitHub and join the mailing list.

Write atleast two blog posts per month

Writing a couple of blog posts a month seems like a pretty easily accomplishable task... But it's probably going to be challenging for me in the beginning. Once I've established the habit of writing this goal should be pretty easy. I'm already half done for January with this post.

I'll be leaning on my first two goals above as some inspiration for content this year. I'll also try to write about general thoughts about my current projects/challenges and inspirations.

Well that is all I have for this first post. I think this was a great start to 2014.