Interfaces โ When Ruby's Duck Typing Meets a Type System
No explicit implements โ if the methods match, the interface is satisfied automatically
Ruby's duck typing: "If it has a quack method, it's a duck." Checked at runtime. Missing method = NoMethodError.
Go's interface: "If it has a quack method, it's a Quacker type." Checked at compile time. Missing method = compile error.
The core difference: same philosophy, but Ruby checks at runtime ("hope it works"), Go checks at compile time ("can't deploy if it doesn't").
Implicit Implementation โ No implements
Java says class Dog implements Animal. Go doesn't:
type Quacker interface { Quack() string }
type Duck struct{}
func (d Duck) Quack() string { return "quack" }
// Duck automatically satisfies the Quacker interface
No declaration that Duck implements Quacker. It has the Quack() string method, so it automatically qualifies. Ruby's duck typing philosophy brought into a type system.
Empty Interface = Ruby's Object
interface{} (or any in Go 1.18+) is satisfied by every type. Like Ruby's Object class. Accepts any value but gives up type safety.
io.Reader, io.Writer โ Power of Small Interfaces
Go's standard library uses tiny interfaces as building blocks. io.Reader requires just one method: Read(p []byte) (n int, err error). Files, HTTP responses, strings, compressed streams โ all satisfy this single interface.
Similar to Ruby's IO objects having a read method, but in Go it's enforced by the type system.
Ruby to Go
Ruby: duck typing (runtime check) โ Go: interface (compile-time duck typing)
Java: explicit implements โ Go: implicit implementation (auto-satisfied if methods match)
Ruby: Object (parent of all) โ Go: interface{}/any (accepts all types)
Keep interfaces small โ 1-2 methods like io.Reader is ideal
Pros
- ✓ Maintains Ruby's duck typing philosophy while guaranteeing compile-time safety
- ✓ No implements declaration needed โ loose coupling between packages
Cons
- ✗ Hard to tell which struct satisfies which interface just by reading code
- ✗ Overusing interface{} (any) makes it no different from Ruby's dynamic typing