Why Go Interfaces Are Different: A Deep Dive for OO Developers
If you are transitioning to Go from object-oriented heavyweights like Java, C#, or C++, you will quickly notice that Go feels different. There are no classes, no inheritance hierarchies, and no implements keyword. Yet, Go is deeply polymorphic. The secret lies in Go interfaces . They are arguably the most powerful and defining feature of the language. But because they don't behave like interfaces…
Go interfaces are fundamentally different from interfaces in object-oriented programming languages like Java or C#. While traditional OOP interfaces require explicit declaration and implementation, Go interfaces are implicit. A type implements an interface by simply providing all the necessary methods. This means a package providing a data writer, like ConsoleWriter, doesn't need to be aware of how other packages will use it. The interface is defined by the consumer, not the producer.
The Go runtime knows a struct satisfies an interface by constructing an iface structure, which contains a pointer to an itab (interface table) and a data pointer. The itab holds metadata about the concrete type and a list of function pointers that map the interface's methods to the concrete type's methods. When calling a method on an interface, the Go runtime uses the tab pointer to find the correct function in the itab and passes the data pointer as the receiver.
This dynamic generation of the itab enables implicit implementation without sacrificing the performance of static typing.
A key aspect of Go interfaces is their small size. Small interfaces, typically containing one or three methods, are highly composable. They enable functions to accept a wide range of types, making code more reusable. For example, the Writer interface in Go is just one method long: type Writer interface { Write (p []byte) (n int, err error) }. This allows functions to accept any type that satisfies the Writer interface, such as io.Writer, os.File, or a custom struct implementing Write.
The design of Go interfaces makes testing easier as well. In traditional OOP, mocking a third-party class requires mocking all its methods, even if only a subset is needed. In Go, you can define a local interface with just the methods your function requires. For instance, if a PaymentGateway struct has many methods but your code only uses the Charge() method, you can define a local Charger interface: type Charger interface { Charge(amount float64) error }.
This approach allows you to test your code without needing to mock all the methods of the third-party struct.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.