Interfaces
Interfaces let you define a set of method signatures that a struct must implement. Any struct that declares itself as implementing an interface is checked by the compiler — if a required method is missing or has the wrong signature, compilation fails.
Spice uses interfaces for virtual dispatch: calling a method through an interface pointer resolves to the correct implementation at runtime via a vtable, without carrying any type information overhead beyond the pointer itself.
Defining an interface¶
Method signatures inside an interface body use the same f/p syntax as regular functions and procedures, but have
no body.
Implementing an interface¶
Attach the interface to a struct with : InterfaceName in the struct declaration. The compiler then requires that
every method declared in the interface is implemented as a method on that struct.
| Spice | |
|---|---|
The method definitions live outside the struct body, exactly like any other method.
Using an interface pointer¶
To call methods through an interface, take a pointer to the concrete value and assign it to a pointer of the interface type. Calling a method on the interface pointer dispatches to the correct implementation at runtime.
| Spice | |
|---|---|
You can also take an interface reference and pass it to a function that only knows about the interface:
| Spice | |
|---|---|
Note
Spice does not allow assigning a struct value directly to an interface variable — you must use a pointer or
reference. The compiler will report an error if you try Driveable car = Car().
Multiple interfaces¶
A struct can implement more than one interface by listing them separated by commas:
| Spice | |
|---|---|
Generic interfaces¶
Interfaces can have generic type parameters, just like generic structs:
Interfaces across source files¶
Interfaces can be defined in one file and used in another. Mark the interface and its method signatures public so
they are visible when imported:
shapes.spice:
main.spice:
Standard library interfaces¶
The standard library ships two interfaces you will encounter frequently:
| Interface | Module | Purpose |
|---|---|---|
IIterable<T> |
std/iterator/iterable |
Marks a type as iterable in a foreach loop |
IIterator<T> |
std/iterator/iterator |
Consumed by foreach to step through elements |
Implementing IIterable<T> on your own collection type makes it work with foreach automatically. See
foreach loops for details.