{
  "$type": "site.standard.document",
  "canonicalUrl": "https://rednafi.com/go/interface-guards/",
  "description": "Use compile-time interface guards to verify type conformity in Go without runtime overhead. Learn the var _ Interface = (*Type)(nil) pattern.",
  "path": "/go/interface-guards/",
  "publishedAt": "2023-08-18T00:00:00.000Z",
  "site": "at://did:plc:fgtm2c26vfcj74rfmeggbyqj/site.standard.publication/3mnl6f7ob462z",
  "tags": [
    "Go",
    "TIL",
    "API"
  ],
  "textContent": "I love Go's implicit interfaces. While convenient, they can also introduce subtle bugs\nunless you're careful. Types expected to conform to certain interfaces can fluidly add or\nremove methods. The compiler will only complain if an identifier anticipates an interface,\nbut is passed a type that doesn't implement that interface. This can be problematic if you\nneed to export types that are required to implement specific interfaces as part of their API\ncontract.\n\nHowever, there's a way you can statically check interface conformity at compile time with\nzero runtime overhead. Turns out, this was always buried in [Effective Go]. Observe:\n\nWe're checking if struct T implements the io.ReadWriter interface. It needs to have both\nRead and Write methods defined. The type conformity is explicitly checked via\nvar _ io.ReadWriter = (T)(nil). It verifies that a nil pointer to a value of type T\nconforms to the io.ReadWriter interface. The code will fail to compile if the type ever\nstops matching the interface.\n\nThis is only possible because nil values in Go can assume many [different types as\nexplained in Go 101]. In this case, var _ io.ReadWriter = T{} will also work, but then\nyou'll have to fiddle with different zero values if the type isn't a struct. One important\nthing to point out is that we're using _ because we don't want to accidentally refer to\nthis nil pointer anywhere in our code. Also, trying to access any method on it will cause\nruntime panic.\n\nHere's another example borrowed from [Uber's style guide]:\n\nNo check:\n\nCheck:\n\nNeat, but don't abuse this. [Effective Go warns]:\n\n> Don't do this for every type that satisfies an interface, though. By convention, such\n> declarations are only used when there are no static conversions already present in the\n> code, which is a rare event.\n\nFurther reading\n\n- [Interface guards - Caddy docs]\n- [Tweet by Matt Boyle]\n\n\n\n\n\n[effective go]:\n    https://go.dev/doc/effective_go#interfaces\n\n[different types as explained in Go 101]:\n    https://go101.org/article/nil.html\n\n\n[uber's style guide]:\n    https://github.com/uber-go/guide/blob/master/style.md#verify-interface-compliance\n\n\n[effective go warns]:\n    https://go.dev/doc/effective_go#interfaces:~:text=The%20appearance%20of,a%20rare%20event\n\n[interface guards - caddy docs]:\n    https://caddyserver.com/docs/extending-caddy#interface-guards\n\n[tweet by matt boyle]:\n    https://twitter.com/MattJamesBoyle/status/1692428212058403251?s=20",
  "title": "Interface guards in Go"
}