ADR 0020: Declared conformance: `struct T : I`
Status: Accepted
Context
Section titled “Context”Interfaces in Go, and so in Lyth, are structural. When a type stops implementing
an interface (a method renamed, a signature changed, a receiver made a
pointer), the error appears at some distant assignment, or nowhere if the only
use is in another package. Go programmers guard against this with
var _ Shape = Circle{} or var _ io.Writer = (*counter)(nil), an idiom that
works but reads as a trick, and whose error is a type mismatch rather than a
missing method.
Decision
Section titled “Decision”- A struct may list the interfaces it implements:
struct Circle : Shape, fmt.Stringer { ... }. The list is optional and changes nothing about method sets, dispatch, or which types implement which interfaces. - The checker verifies each entry once all methods of the package are known:
Tor*Tmust implement the interface. If neither does, E0212 at the entry names the method, the signature the interface needs, and the reason (missing, a different signature, notpub). - Each entry lowers to Go’s assertion:
var _ I = T{}, orvar _ I = (*T)(nil)when only the pointer type implementsI. - Only interfaces may be listed. Anything else is E0201, with a note that Lyth has no inheritance.
Alternatives
Section titled “Alternatives”- Nominal interfaces (declaration required): would break interoperability, where Go types implement Lyth interfaces and Lyth types implement Go interfaces without knowing about each other.
- An annotation (
@implements(Shape)): Lyth has no annotations, and the header form is familiar from Kotlin, Swift, and Rust’simplblocks. - Writing Go’s idiom in Lyth (
val _: Shape = Circle()): it works, but the intent is implicit and the diagnostic is generic. - Stating the receiver (
struct T : *I): unnecessary, since the checker knows which ofTand*TimplementsI, and the generated assertion shows it.
Consequences
Section titled “Consequences”Conformance becomes documentation that the compiler keeps true, at no cost beyond Go’s own idiom. Code that omits the list behaves exactly as before. Struct embedding and generic structs, when they arrive, use the same header without conflict, because only interfaces may follow the colon.