A cool golang interface trick

August 7 2015

While working on juju, I noticed a curious code snippet:

var (
	stepPrepare = executorStep{"preparing", Operation.Prepare}
	stepExecute = executorStep{"executing", Operation.Execute}
	stepCommit  = executorStep{"committing", Operation.Commit}
)

where Operation is an interface:

type Operation interface {
	Prepare(state State) (*State, error)
	Execute(state State) (*State, error)
	Commit(state State) (*State, error)
}

Surely, storing a method of an interface definition as a variable makes no sense. But then again, what is the type of an interface method? Let’s check:

package main

import "fmt"

type A interface {
    Run(param string) string
}

func main() {
    fmt.Printf("%T", A.Run)
}

The output is

func(main.A, string) string
Program exited.

We can see that the method is actually a function taking the receiver as its first parameter. Can we use it as a first class citizen? Let’s see:

package main

import "fmt"

type A interface {
    RunA(param string) string
    RunB(param string) string
}

type impl struct {}

func (impl) RunA(param string) string {
    return "ran A: " + param
}

func (impl) RunB(param string) string {
    return "ran B: " + param
}

func execute(on A, runner func(A, string)string) string {
    return runner(on, "hey!")
}

func main() {
    fmt.Println(execute(impl{}, A.RunA))
    fmt.Println(execute(impl{}, A.RunB))
}

And the output we get:

ran A: hey!
ran B: hey!

Program exited.

Neat! So we can actually specify which method to run on an interface implementation without bulky switches and constants!