Namespaces Are Useful

Or: How I Got Bitten by the Dot Import Gotcha

I was extending Gorgonia for a project of mine when I rapidly ran into a dot-import gotcha in Go. Specifically I was trying to implement a fused version of the Conv2d function that exists. The current Conv2d function works well, if you want to do image convolution related work. It could be quite a bit faster (if anyone from Intel is reading, I’d love some help in the same way Intel boosted the speeds of Caffe), but that’s not really the concern - different convolution algorithms have different performance characteristics, and should be used accordingly.

Anyway, here’s the project directory:

PROJECT/
├── ops/
│   ├── convolution.go
│   ├── convolution_nocuda.go
│   └── convolution_cuda.go
│   
├── main.go

The Conv2d function I was writing was in ops/convolution.go. It looked something like this:

package ops

import (
	"gorgonia.org/gorgonia"
	"gorgonia.org/tensor"
)

func Conv2d(im, filter *gorgonia.Node, kernelShape tensor.Shape, pad, stride, dilation []int) (retVal *gorgonia.Node, err error) {
	return nil, nil // actual code here, 
}

I go-built it, and ran into this error message:

$ go build .
./convolution.go:12:6: Conv2d redeclared in this block
	previous declaration during import "gorgonia.org/gorgonia"

WTF?

As it turns out, it’s because I had this import in convolution_nocuda.go, which actually implemented the op:

import (
	. "gorgonia.org/gorgonia"
)

I had used it as a dot-import because unqualified imports look more like I’m writing parts of the Gorgonia package. I had assumed that the dot-imports were unqualified per-file. It’s not. It’s unqualified throughout the package.

The solution is simple: namespaces are useful. Use them.

comments powered by Disqus