# SciJava Ops API: a foundation for a flexible, extensible algorithms framework
This component comprises the abstract foundation for the collection and use of Ops (see SciJava Ops SPI for the declaration of Ops).
## The `OpEnvironment`
The `OpEnvironment` is intended to be the main interface for accessing Ops and has API designed to disconnect algorithm from implementation. Instead of identifying a particular implementation, Ops are retrieved through the `OpEnvironment` by specifying:
* a name
* a set of input types
* an output type
* a functional type
for example, suppose you are looking for a [`java.util.BiFunction`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/function/BiFunction.html) that adds two `Number`s. To obtain an Op that can perform this operation, you might specify:
| Parameter | Value |
|--|--|
| Name | `"add"` |
| Input Types | `{Number, Number}` |
| Output Type | `{Number}`|
| Functional Type | `BiFunction`|
To create *generic* typings, `OpEnvironment` often makes use of the `Nil` interface of SciJava Types. Anonymous `Nil`s are easily created for generic type `X` using `new Nil() {}`. For example, to preserve the functional type in the above table we write `new Nil>() {}`.
In situations where the `OpEnvironment` knows of multiple satisfying Ops, it is up to the `OpEnvironment` to return the "best Op for the job". By delegating the decision to the `OpEnvironment`, the user can spend less time drowning in implementation documentation and construct an image processing chain faster.
To match the `BiFunction` above, we write the following:
``` java
Nil> funcNil = new Nil>() {};
Nil numNil = new Nil() {};
BiFunction foo = op("add", funcNil , new Nil[] {numNil, numNil}, numNil);
```
## `OpBuilder` can be used to simplify Op retrieval
By using `OpBuilder`, we can make this process *much* easier to read. All Op calls using the `OpBuilder` follow a similar pattern:
1. Specify the name of the Op using either `new OpBuilder(OpEnvironment env, String name)` or `OpEnvironment.op(String name)`
2. Specify the input using:
* `OpBuilder.input(I1 in1, I2 in2, ...)`
* `OpBuilder.inType(Nil in1Type, Nil in2Type, ...)`
* `OpBuilder.inType(Class in1Class, Class, ...)`
3. Specify the output using:
* `OpBuilder.output(O out)`
* `OpBuilder.outType(Nil outType)`
* `OpBuilder.outTyep(Class outType)`
4. Specify the desired return using:
* For computers, `OpBuilder.computer()` to get the `Computer` or `compute()` to compute the result directly
* For functions, `OpBuilder.function()` to get the `Function` or `apply()` to compute the result directly
* For inplaces, `OpBuilder.inplace()` to get the `Inplace` or `mutateX()` to compute the result directly (where `X` indicates the index of the argument to be mutated)
Thus we can replace the code:
``` java
Nil> funcNil = new Nil>() {};
Nil numNil = new Nil() {};
BiFunction foo = op("add", funcNil , new Nil[] {numNil, numNil}, numNil);
```
with the code:
``` java
Nil numNil = new Nil() {};
BiFunction foo = op("add") //
.inType(Number.class, Number.class) //
.outType(Number.class) //
.function();
```
Much more readable, no?
## `Hints` and `OpHints` can specify decision preferences
`OpEnvironment` implementations have the ability to respond to a set of `Hints` triggered by the user or by the Ops known to it.
Suppose, for example, that a subset of the Ops known to your `OpEnvironment` specialize in performance, making drastic improvements in speed at the cost of computational accuracy. Through the `OpHints` annotation, these Ops can notify the `OpEnvironment` of their lossiness:
```java
@OpHints(hints = {Lossiness.LOSSY})
public class FastOp implements BiFunction {
@Override
public Number apply(Number in1, Number in2) {
...
}
}
@OpHints(hints = {Lossiness.LOSSLESS})
public class PreciseOp implements BiFunction {
@Override
public Number apply(Number in1, Number in2) {
...
}
}
```
In situations where precision should be prioritized, users can then tell their `OpEnvironment` to prioritize Ops that do not trade performance for speed.
```java
Hints hints = ...;
OpEnvironment env = ...;
public static void main(String[] args) {
hints.setHint(Lossiness.LOSSLESS);
env.setHints(hints);
}
```