LEVIATHAN v962456e · 962456eee1

Declarations

Interfaces

Declare the members a class must provide, including fields, and let any class satisfy them by declaring those members.

since 0.1.0-alpha.1linuxwindowswasm

Description

An interface lists the members that an implementing class must have:

interface IName {
    int x;
    string f();
}

An interface can require fields as well as methods. It does not allocate anything: it only states what must be present. The class that lists the interface after its colon supplies the members and is the only place a field is allocated. As a result two interfaces can require the same field without conflict, and the class holds a single field for both.

A variable whose type is an interface can hold an object of any class that implements it, and calls through it dispatch on the object's class.

Implementing two interfaces that share a field

interface INamed { string name; string describe(); }
interface IAged { int age; string name; }
class Person : INamed, IAged {
    string name = "Ada";
    int age = 36;
    string describe() => name + " (" + age.toString() + ")";
}
INamed n = Person();
console.writeln(n.describe());
IAged g = Person();
console.writeln(g.age);
console.writeln(g.name);
Ada (36)
36
Ada

Rules

  • A class satisfies an interface when it provides every required member. A missing member, or a member with the wrong type, is a compile error naming the unsatisfied requirement. A member that satisfies a requirement may be marked override (lang.override).
  • A method satisfies a required method when the names and the parameter types match exactly and the method's return type is assignable to the required return type.
  • Interface method returns are covariant: a method may declare a return type that is a class (or interface) derived from the required return type. A class DogFinder whose find returns Dog satisfies an interface requiring Animal find().
  • A class or interface return type T also satisfies a required T?. Other optional and union returns, function types, primitives and void must match the requirement exactly.
  • Covariance applies only to satisfying an interface. Narrowing the return type of a method in a derived class does not override the base class's method; it declares a separate method, and calls through the base type still reach the base class's method.
  • Requirements allocate no slot, so dispatch through an interface variable reaches the implementing class's single method.

Examples

A class can return a more specific type than the interface requires, including where the requirement is optional:

Covariant return types

class Animal { string kind() => "animal"; }
class Dog : Animal { string kind() => "dog"; }
interface IFinder { Animal find(); Animal? maybeFind(); }
class DogFinder : IFinder {
    Dog find() => Dog();
    Dog maybeFind() => Dog();
}
IFinder f = DogFinder();
console.writeln(f.find().kind());
Animal? a = f.maybeFind();
if (a != None) {
    console.writeln(a.kind());
}
dog
dog

Narrowing a return type in a subclass does not override:

Covariance is for interface satisfaction only

class Animal { string kind() => "animal"; }
class Dog : Animal { string kind() => "dog"; }
class Kennel {
    Animal pick() => Animal();
}
class DogKennel : Kennel {
    Dog pick() => Dog();
}
Kennel k = DogKennel();
console.writeln(k.pick().kind());
animal

An unsatisfied requirement is reported when the class is declared:

A missing member

interface INamed { string name; string describe(); }
class Person : INamed {
    string name = "Ada";
}
// error: 'Person' does not satisfy interface: missing 'describe : () -> string'
not run — a compile error on purpose

A required optional return is satisfied by the plain type:

T satisfies T?

class Animal { string kind() => "animal"; }
interface IFinder { Animal? find(); }
class AF : IFinder {
    Animal find() => Animal();
}
not run — blocked by an open compiler bug

See also

  • Classes — Declare reference types with fields, methods, constructors and accessors, with generics and inheritance from one or more base classes.
  • Multiple inheritance — Combine several base classes, how same-named fields and methods collapse or stay separate, and how to reach one base's member by qualification.