# `nupp.spi`
Discover implementations, then choose with ordinary module initialization code.
`load(Interface)` returns a lazy iterator in dependency order. Iteration order
does not choose a winner: the caller may compare priorities, check capabilities,
or combine implementations. `select` is the common rule, the unique highest
`priority`, with the caller's fallback where nothing is advertised:
```nupp:fragment
local spi = require("nupp.spi")
local {type Codec} = require("example.codec.spi")
local impl: Codec = spi.select(spi.load(Codec)) ?? require("example.defaultcodec")
```
Keep the selected functions when the module loads. Packages advertise their
implementation modules in `nupp/spi.json`.
## Functions
### `load` _function_
```nupp
load(Interface): function(): Interface?
```
Iterates implementations of an exported interface without choosing one.
Call as `nupp.spi.load(Interface)`, passing the interface declaration.
Each iteration loads one module; ordinary require caching retains its identity.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `Interface` | `interface declaration` | The exported interface whose implementations to discover. |
#### Returns
| Type | Description |
| --- | --- |
| `function(): Interface?` | A lazy iterator of implementations, returning nil at exhaustion. |
#### Raises
| Type | Condition |
| --- | --- |
| `any` | whatever an implementation raised while loading, which is that module's business rather than this one's; the next call retries it |
### `select` _function_
```nupp
function select(candidates: function(): I?): I?
```
Chooses the implementation with the unique highest `priority`.
Call as `nupp.spi.select(nupp.spi.load(Interface)) ?? fallback`: nil where
nothing is advertised, so the fallback is loaded only when it is used.
An implementation that states no priority counts as 0, and a higher priority
supersedes a tie below it. Discovery order never breaks a tie for the highest.
#### Type parameters
| Name | Description |
| --- | --- |
| `I` | |
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `candidates` | `function(): I?` | The implementations to choose among, usually what `load` answered. |
#### Returns
| Type | Description |
| --- | --- |
| `I?` | The implementation with the highest priority, or nil where there is none. |
#### Raises
| Type | Condition |
| --- | --- |
| `string` | where two implementations share the highest priority |
| `any` | whatever an implementation raised while loading |