Protocols
A protocol is a contract. It lists the members a type must provide without saying how they work. It is the same idea as an interface in other languages.
PROTOCOL Domain/Repository:
PUBLIC findById(Integer): ?Domain/Entity/User
PUBLIC save(Domain/Entity/User): Boolean
Any type that claims to be a Domain/Repository promises to supply a findById and
a save with those exact shapes. The protocol supplies no implementation and only
states the requirement.
What a protocol may declare
A protocol follows the same member rules as a struct: every member starts with a visibility keyword. Unlike a struct, it may declare both properties and methods:
PROTOCOL Base/Entity:
PUBLIC getIdentifier(): UUID # a required method
PUBLIC value: String # a required property
Methods here are signatures only: a name, parameters and an optional return type, with no functional intent. A protocol states what is required and leaves how to whatever implements it.
Using a protocol
Protocols are used in two places. First, as an ordinary type. A parameter or return type can be a protocol, which asks for anything that satisfies the contract:
PROTOCOL Shape:
PUBLIC area(): Float
FUNCTION totalArea(shapes: Array[Shape]): Float
> sum the area of every shape
> return the sum
totalArea accepts circles or squares, as long as each one has an area().
Then a CLASS can declare that it implements a protocol with the promise to
fulfill the contract:
CLASS Circle IMPLEMENTS Shape:
PUBLIC radius: Float
PUBLIC area(): Float
Tooling checks the IMPLEMENTS link. If Circle claimed to implement Shape but
had no area(), the linter would report it.
Protocols let you design against a contract rather than a concrete type.