Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Interface Types

An interface (or “power” in natural syntax) defines a contract: a set of method signatures that a type must provide. Interfaces enable polymorphism in Forge — any type that satisfies an interface’s contract can be used wherever that interface is expected.

Definition

Interfaces are defined with the interface keyword (classic) or the power keyword (natural).

InterfaceDef → ( interface | power ) Identifier { MethodSignature* }

MethodSignaturefn Identifier ( ParamList? ) ( -> Type )?

// Classic syntax
interface Describable {
    fn describe() -> String
}

// Natural syntax — identical result
power Describable {
    fn describe() -> String
}

An interface body contains one or more method signatures. Each signature specifies the method name, parameter types, and optional return type. No method body is provided — interfaces declare what methods must exist, not how they work.

Implementing an Interface

A type satisfies an interface by providing implementations of all required methods. This is done using give ... the power ... (natural) or impl ... for ... (classic).

thing Person {
    name: String,
    age: Int
}

// Natural syntax
give Person the power Describable {
    define describe(it) {
        return it.name + " (" + str(it.age) + ")"
    }
}

// Classic syntax — identical result
impl Describable for Person {
    fn describe(it) {
        return it.name + " (" + str(it.age) + ")"
    }
}

The implementation block must provide a method for every signature in the interface. Missing methods produce a compile-time (definition-time) error.

Checking Satisfaction

The satisfies() built-in function checks whether a value’s type satisfies a given interface at runtime:

set alice to craft Person { name: "Alice", age: 30 }
say satisfies(alice, Describable)   // true

If a type has not implemented the interface, satisfies() returns false:

thing Robot {
    id: Int
}

set r to craft Robot { id: 1 }
say satisfies(r, Describable)   // false

Multiple Interfaces

A single type may implement multiple interfaces:

power Describable {
    fn describe() -> String
}

power Vocal {
    fn speak() -> String
}

thing Animal {
    species: String,
    sound: String
}

give Animal the power Describable {
    define describe(it) {
        return it.species + " that says " + it.sound
    }
}

give Animal the power Vocal {
    define speak(it) {
        return it.sound + "! " + it.sound + "!"
    }
}

Each interface implementation is provided in a separate give...the power block. A type accumulates all its interface implementations.

No Default Implementations

In the current version of Forge, interfaces cannot provide default method implementations. Every method in an interface must be explicitly implemented by each type that satisfies it.

Interface Inheritance

Interface inheritance (one interface extending another) is not supported in the current version. Each interface is independent.

Structural vs. Nominal

Forge uses a nominal approach to interface satisfaction: a type satisfies an interface only if it has been explicitly declared to do so via a give...the power or impl...for block. Simply having methods with matching names and signatures is not sufficient.

However, the satisfies() built-in performs a structural check at runtime — it verifies that the required methods actually exist on the value. This means satisfaction is ultimately determined by the presence of the declared methods, but the declaration is required to register the type-interface relationship.