๐Ÿฆ†

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

1

Ruby: duck typing (runtime check) โ†’ Go: interface (compile-time duck typing)

2

Java: explicit implements โ†’ Go: implicit implementation (auto-satisfied if methods match)

3

Ruby: Object (parent of all) โ†’ Go: interface{}/any (accepts all types)

4

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

Use Cases

When converting Ruby's respond_to? pattern to Go's interface type check

References