# Chapter 10: Interfaces

An interface names a set of methods. A class or struct that declares `implements` the interface and provides those methods can be used wherever the interface is expected. This chapter covers declaring and implementing interfaces, default methods, the built-in interfaces that the language itself uses (`Iterable`, `Iterator`, `Comparable`, `Scoped`, `Sendable`, `Finalizable`), and interfaces as constraints on generic code.

## Declaring and implementing an interface

An interface lists method signatures, each ending in `;`. A type opts in with `implements` and defines every method:

```loup
@mode(host.native)

interface Shape {
    func area(): float;
    func name(): string;
}

class Circle implements Shape {
    pub let radius: float;
    new(radius: float) { this.radius = radius; }
    pub func area(): float { return 3.14159 * this.radius * this.radius; }
    pub func name(): string { return "circle"; }
}

struct Rectangle implements Shape {
    width: float;
    height: float;
    pub func area(): float { return this.width * this.height; }
    pub func name(): string { return "rectangle"; }
}

func totalArea(shapes: list[Shape]): float {
    var sum = 0.0;
    for (s in shapes) {
        sum = sum + s.area();
    }
    return sum;
}

func main(): void {
    let shapes: list[Shape] = [Circle(1.0), Rectangle(width = 2.0, height = 3.0)];
    for (s in shapes) {
        println(i"{$ s.name() $}: {$ s.area() $}");
    }
    println(totalArea(shapes));
}
```

*Listing 10-1: A class and a struct behind one interface*

```text
circle: 3.14159
rectangle: 6
9.14159
```

A call through an interface is dispatched on the value's actual type at run time, as with class inheritance (chapter 9). A class combines a base class and interfaces as `class Dog : Animal implements Named, Comparable[Dog]`.

### Mistake: relying on structural typing

Go and TypeScript treat any type with the right methods as satisfying an interface. Loup's interfaces are nominal: a type must say `implements`:

```loup,does_not_compile
@mode(host.native)

interface Shape {
    func area(): float;
}

class Square {
    pub let side: float;
    new(side: float) { this.side = side; }
    pub func area(): float { return this.side * this.side; }
}

func main(): void {
    let s: Shape = Square(2.0);
    println(s.area());
}
```

```text
main.lphc:14:5: error[E0001]: cannot assign 'Square' to binding 's' of type 'Shape'
```

Add `implements Shape` to the class.

### Mistake: an incomplete implementation

Declaring `implements` is a promise to provide every method, with the declared types:

```loup,does_not_compile
@mode(host.native)

interface Shape {
    func area(): float;
    func name(): string;
}

class Square implements Shape {
    pub let side: float;
    new(side: float) { this.side = side; }
    pub func area(): float { return this.side * this.side; }
}

func main(): void {
    let s: Shape = Square(2.0);
    println(s.area());
}
```

```text
main.lphc:8:1: error[E0001]: class 'Square' does not implement all methods of interface 'Shape'; missing: name(): string
```

The message lists each missing method with its signature. A method with the right name but the wrong return type is reported too: "method 'area' in class 'Square' has return type 'int', incompatible with interface 'Shape' return type 'float'".

**Known gap.** Stage0 1.25.1 performs this check for classes only. A `struct … implements Shape` that leaves out a method compiles, and fails only if the missing method is called. Rely on the class check, and test struct implementations.

## Default methods

An interface method can have a body. Implementing types inherit it and may override it:

```loup
#~ @mode(host.native)
interface Shape {
    func area(): float;
    func name(): string;
    func describe(): string {
        return i"{$ this.name() $} with area {$ this.area() $}";
    }
}

class Circle implements Shape {
    pub let radius: float;
    new(radius: float) { this.radius = radius; }
    pub func area(): float { return 3.0 * this.radius * this.radius; }
    pub func name(): string { return "circle"; }
}

func main(): void {
    let c: Shape = Circle(2.0);
    println(c.describe());
}
```

*Listing 10-2: A default method*

```text
circle with area 12
```

**Known gap.** A default method called on a *struct* stops `loup run` with `internal interpreter limitation: unsupported instruction: CallVirtual describe on user class … — method not found`. Until that is fixed, give structs their own implementation of every method.

## Interfaces the language uses

### `Iterable[T]` and `Iterator[T]`

A `for (x in value)` loop works on any value whose type implements `Iterable[T]`, which has one method, `iter()`, returning an `Iterator[T]`. An iterator's `next()` returns `Some(item)` until it returns `None`:

```loup
#~ @mode(host.native)
class PageIter implements Iterator[int] {
    var page: int;
    let last: int;
    new(first: int, last: int) {
        this.page = first;
        this.last = last;
    }
    pub modifier func next(): Option[int] {
        if (this.page > this.last) {
            return None;
        }
        let current = this.page;
        this.page = this.page + 1;
        return Some(current);
    }
}

class PageRange implements Iterable[int] {
    let first: int;
    let last: int;
    new(first: int, last: int) {
        this.first = first;
        this.last = last;
    }
    pub func iter(): Iterator[int] {
        return PageIter(this.first, this.last);
    }
}

func main(): void {
    for (page in PageRange(3, 5)) {
        println(i"fetching page {$ page $}");
    }
}
```

*Listing 10-3: A custom iterable*

```text
fetching page 3
fetching page 4
fetching page 5
```

`next()` changes the iterator, so it is a `modifier`. A `gen func` (chapter 4) is a shorter way to produce a sequence.

### `Comparable[T]`

`Comparable[T]` has one method, `compareTo(other: T): int`, returning a negative number, zero, or a positive number. Implementing it gives a type `<`, `<=`, `>`, `>=` and `==`. `int`, `float` and `string` implement it already:

```loup
#~ @mode(host.native)
class Version implements Comparable[Version] {
    pub let major: int;
    pub let minor: int;
    new(major: int, minor: int) {
        this.major = major;
        this.minor = minor;
    }
    pub func compareTo(other: Version): int {
        if (this.major != other.major) {
            return this.major - other.major;
        }
        return this.minor - other.minor;
    }
}

func main(): void {
    let installed = Version(1, 9);
    let available = Version(2, 0);
    if (installed < available) {
        println(i"upgrade to {$ available.major $}.{$ available.minor $}");
    }
}
```

*Listing 10-4: Ordering versions*

```text
upgrade to 2.0
```

### `Scoped[T]`

A type that implements `Scoped[T]` (methods `scope_enter(): T` and `scope_exit(error: Option[Exception]): bool`) can be used in a `with` block, which calls both on every path out of the block. Listing 5-8 is a complete example.

### `Finalizable`

A class with a `func finalize(): void` method implements `Finalizable` implicitly; writing `implements Finalizable` is allowed and documents the intent. Chapter 9 explains when `finalize()` runs.

### `Sendable`

`Sendable` has no methods. It marks a type whose values may be handed to another thread (runtime volume §2-1.8). Primitives, strings and structs of Sendable fields qualify automatically. A class must declare it, and the compiler then checks that every `var` field is protected by a `Mutex[T]`, `RwLock[T]` or `Atomic[T]`:

```loup,does_not_compile
@mode(host.native)

class RequestCounter implements Sendable {
    var count: int = 0;
}

func main(): void {
    let c = RequestCounter();
}
```

```text
main.lphc:4:5: error[E_SENDABLE_UNPROTECTED_VAR]: var field 'count' on Sendable class 'RequestCounter' must be of type Mutex[T], RwLock[T], or Atomic[T], not 'int'
```

A `let` field is never written after construction, so it needs no protection. A `synchronized class` (chapter 15) protects its fields with its own lock and may declare `Sendable` with plain `var` fields. Chapter 20 covers threads.

## Interfaces as generic constraints

A generic function can require its type parameter to implement an interface, and then call the interface's methods on it. Write the bound in a `where` clause after the return type:

```loup
#~ @mode(host.native)
#~ interface Shape {
#~     func area(): float;
#~     func name(): string;
#~ }
#~ struct Rectangle implements Shape {
#~     width: float;
#~     height: float;
#~     pub func area(): float { return this.width * this.height; }
#~     pub func name(): string { return "rectangle"; }
#~ }
func largest[T](items: list[T]): T where T: Comparable[T] {
    var best = items[0];
    for (x in items) {
        if (x > best) {
            best = x;
        }
    }
    return best;
}

func label[S](shape: S): string where S: Shape {
    return i"{$ shape.name() $} ({$ shape.area() $})";
}

func main(): void {
    println(largest([3, 9, 2]));
    println(largest(["pear", "apple", "zucchini"]));
    println(label(Rectangle(width = 2.0, height = 2.5)));
}
```

*Listing 10-5: `where` bounds*

```text
9
zucchini
rectangle (5)
```

Unlike a `list[Shape]` parameter, a bounded type parameter keeps the concrete type: `largest` returns an `int` for a list of `int`. The inline form of the bound, `func largest[T: Comparable[T]](…)`, is also specified, but in 1.25.1 it does not let the body call the interface's methods; chapter 11 shows the error.

Chapter 18 covers interfaces with lifetime parameters.

## Summary

- `interface I { func m(): T; }` declares methods; `class C implements I` and `struct S implements I` opt in. Interfaces are nominal (`cannot assign 'Square' to … 'Shape'` without `implements`).
- A class that omits an interface method is rejected; a struct is not checked in 1.25.1.
- Interface methods may have default bodies; calling one on a struct fails under `loup run` today.
- `Iterable[T]`/`Iterator[T]` drive `for` loops; `Comparable[T]` (`compareTo` returning `int`) gives `<`, `>`, `==`; `Scoped[T]` drives `with`; `finalize()` makes a class `Finalizable`.
- `Sendable` classes must protect every `var` field (`E_SENDABLE_UNPROTECTED_VAR`).
- Use `where T: I` to constrain a generic and call `I`'s methods on `T`.
- Chapter 11 covers generics.
