Go's reflect packages vs types package

I’m attempting to migrate some code that uses reflect to instead use go/types and I have some thoughts.

I’m attempting to migrate the easyjson tool from being reflect based to being go/types based. The main reason is so that it won’t take so long on our repo when we do go generate. Here are some random takeaways from this project, so far.

First off, for my purposes reflect has one relevant entrypoint function (TypeOf) and a single god type (Type.) You pass the value you have to reflect.TypeOf, get back a reflect.Type, typically look at it’s Kind method, maybe the Implements method, and then based on those you can inspect from there. If the kind is a Map, for example, you’ll be able to look at the Key method and the Elem method to find out the inner types.

The go/types interface, interestingly, feels much more “Go” than reflect. Instead of switching on a Kind field and avoiding the wrong methods (because they’ll panic) you do a type switch on the “surface” interface (types.Type) and then get a concrete type that only has the methods you can use. It’s safer to use, but you have to know more to use it.

While reflect only requires you to pass in a value to give you a reflect.Type, to get a types.Type you probably have to somehow parse Go. Typically you’ll do this with go/ast. (There’s another package that wraps both go/ast and go/types called golang.org/x/tools/go/packages, which makes things easier.)

The biggest hassle for me so far (because I hadn’t fully digested what types.Info makes available) has been naming. reflect.Type has both Name and PkgPath methods. This means that it’s cake to just get the name of the type you had. types.Type on the other hand, will only have a Name (and PkgPath) if it’s a *types.Named; if you got one of those (and indeed even if you didn’t) you can then access the Underlying method to get at the actual type. If you didn’t get a *types.Named, chances are you are just doing something wrong. I was accessing the Types field in the Info struct and should have actually been accessing the Defs field. There are other ways to get at this data, but some will have names and some won’t.

Hopefully I can blog again soon about the results of this!

(The following includes affiliate links.)

If you are interested in learning Go, this is my recommendation:

If you don’t already know Go, you should definitely check out The Go Programming Language. It’s not just a great Go book but a great programming book in general with a generous dollop of concurrency.

Another book to consider learning Go with is Go Programming Blueprints. It has a nearly interactive style where you write code, see it get syntax errors (or whatever,) fix it, and iterate. A useful book that shows that you don’t have to get all of your programs perfectly working on the first compile.

Posted Tue, Oct 22, 2019

If you're interested in being notified when new posts are published, you can subscribe here; you'll get an email once a week at the most.