Go

How is an interface value represented at runtime? What is the difference between iface and eface?

Question 77HardGo 1.22 to 1.25

An interface value is a two-word structure. The runtime uses two layouts:

  • eface (empty interface, any): {_type *_type; data unsafe.Pointer}. It holds only the dynamic type descriptor and a pointer to the data.
  • iface (non-empty interface): {tab *itab; data unsafe.Pointer}. The itab holds the interface type, the concrete type, a hash and the table of method pointers used for dynamic dispatch.
// simplified from runtime/runtime2.go (itab lives in internal/abi as abi.ITab since Go 1.22)
type eface struct {
    _type *_type
    data  unsafe.Pointer
}

type iface struct {
    tab  *itab
    data unsafe.Pointer
}

type itab struct {
    inter *interfacetype // the static interface type
    _type *_type         // the dynamic (concrete) type
    hash  uint32         // copy of _type.hash, used by type switches
    fun   [1]uintptr     // variable-sized method table; fun[0]==0 means T does not implement inter
}

If the concrete value is pointer-shaped (a pointer, map, chan, func, or single-pointer struct), data holds it directly. Otherwise the value is copied to the heap, or to static read-only data for constants, zero-sized values and small integers, and data points at the copy. An interface is nil only when both words are nil.

What the interviewer wants to hear: the two-word layout, that storing a value in an interface copies it, and how this explains the "nil interface vs typed nil" bug.

More on Interfaces, Methods & Embedding

All 35 Interfaces, Methods & Embedding questions