Ramblings of an aging IT geek
← Ramblings of an aging IT geek
golang

the function signature that accepts everything and promises nothing

A short note on why a Go function returning interface{} pushed all my type checks to runtime, and where I drew the line.

Code on a screen, shallow focus

I found a function this week that returned interface{} and felt a small, specific dread, because I wrote it and I knew exactly what it had done to everything downstream. An empty interface accepts any value, which sounds like flexibility and is actually an abdication. You've told the compiler to stop helping, and it obliges.

The cost isn't visible at the call site that produces it. It's visible at every site that consumes it, each one forced into a type assertion, each one carrying a , ok and a runtime error path for the case where the value isn't what you assumed. Get it wrong and you don't find out at build time. You find out when the wrong type sails through, the assertion fails, and something panics on the box you can't reach, which is precisely where I found out.

The honest fix was boring. Where I knew the type, I returned the type. A struct, a concrete return value, a real signature that says what comes back. The verbosity I'd been avoiding turned out to be the compiler offering to check my work, and I'd been declining.

I still keep interface{} for the genuine edges, the formless JSON, the variadic logger, the places where the type really is unknown until runtime. Everywhere else it was laziness wearing the costume of generality. If a value's shape is knowable, make it known, and let the build break in the editor rather than in production at two in the morning.