16 · activate / deactivate

Reactive coeffects

If the previous dimension was about how a piece modifies its environment, this one is about what it needs from it.

The starting point is a table mapping names to capabilities, recognisable to anyone who has used dependency injection.

The elegant part is what happens next. Registering a dependency in that table has exactly the shape of a change to the environment, so the machinery from the previous chapter applies untouched. Dependencies are tracked and removed like any other effect.

Activate and deactivate

Reaching for something that is not there is a runtime error. The reasonable thing is for a piece to activate only when everything it declares is available.

Because every change to the table goes through the same mechanism, every change can be classified on the spot.

ChangeWhenWhat the system does
activationThe piece now has everything it asked forStarts it up
deactivationIt stops having itApplies its stack of inverses and removes it
irrelevantNothing it asked for changedNothing

The half this mechanism does not solve

This is where you notice the paper does not settle.

The ordering between provider and consumer only works in one direction. If A provides something and B needs it, B cannot activate before A.

The other way round fails. Unloading A breaks what B needed, but a notification on its own cannot keep the capability available for the whole of B’s teardown, nor hold back A’s cleanup until B has finished.

Two useful extensions

  • Extension one Isolation Lets the same name resolve to different things depending on who is asking. Useful for multi-tenancy, for testing and for restricted environments.
  • Extension two Interception Lets the surrounding environment condition how a piece uses a capability, without touching that piece code. Environment settings take precedence over the ones the piece declares.

The bridge between the two dimensions

This is the most beautiful part of the paper and the one summaries lose most often.

The independence from the previous section, which is what allows undoing in any order, does not have to be assumed. It derives from a property of the dependencies.

Two pieces operating on different names are independent, full stop. And if they share a name, it is enough for that name to have an interface where order does not matter.

The temporal dimension rests on the spatial one. And that turns an abstract mathematical condition into a concrete interface design decision.