Wandering Thoughts archives

2013-02-10

A little irritating (but understandable) limitation on Go interfaces

I was all set to write an entry about how you could use Go-style interfaces to create what I called easy, type-safe conversions from a variety of types to something you wanted. The sketch of the problem and the idea is that suppose you want to create an API that accepts arguments in multiple forms (eg), for example something in uncompiled string form or in a compiled efficient form. The usual way to implement this is with a type switch in your functions ('if argument is a string, convert it to ...') but this annoying and limited. Interfaces to the rescue, in theory: define a 'Converter' interface with a single 'ToMyThing()' method, make your API take Converter arguments (and your functions then call arg.ToMyThing()), and define a new ToMyThing() method on strings, integers, and whatever else you want to accept.

(The ToMyThing() method for your actual type does nothing and just returns itself.)

People who know Go are shaking their head sadly right about now. Here, let me tell you why:

prog.go:9: cannot define new methods on non-local type string

Well, oops. So much for that.

If you understand how Go's types and interfaces are implemented, this makes sense. One of the parts of the type description for every concrete Go type is a static, fixed array of methods (with various information including their name and a function pointer); this is built as the type is compiled. What this error message really means is 'the method array for string has already been built, you can't add entries to it now'.

It's not hard to see why allowing this would massively complicate Go's life. The big reason is that entries in the method array are sorted by name (for good reason). Adding a name to it after the type has been compiled means re-sorting the array, changing the index position of entries, and then finding and changing all references to now-invalid index positions in already compiled code. In practice you would want to defer the index position resolution until link time (as a form of link time relocation) and I'm not sure that's even possible in object formats like ELF. Certainly it would add a lot more complexity to the whole process.

(Actually it's even worse; you would have to defer building the method table entirely until link time, since you might have to merge together string method definitions from all over your code base.)

You would also open up the possibility of weird link-time errors. For example, suppose that two separate bits of Go code both independently decide to add (different) Convert() methods to string. This pretty much has to be an error, but it's something you can only detect and report at link time. Worse, those bits of Go code work independently; they only fail when you combine them into a single program. This is not a recipe for good software engineering and I'm not at all surprised that Go left this out.

programming/GoInterfacesLimitation written at 02:00:16; Add Comment


Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.