The source code are mostly to the way dynamic sealing is implemented:
Brand.create[String]is now just
sealer.apply[String]("hello"), so the
Stringtype is added by the sealer.
Brand.Box[String]and the unsealer are the same.
- Brand hints are applied to everything, so that you can tell whether a sealer and an unsealer belong to the same brand.
Unsealerare full on traits, instead of type aliases.
The impetus for changing dynamic sealing around was implementing responsibility tracking aka HORTON in Scala.
Responsibility tracking addresses an argument made against capabilities – because capabilities don't have an implicit identity associated with them, you don't know how they are being used and who is using them. Horton addresses this by using dynamic sealing to encode objects as "gifts", which are sealed boxes that can only be unsealed by the recipient, and return proxies which indicate their provenance.
So, assuming some traits
C and some proxy boilerplate code:
We'll get the following output:
Because Horton uses stubs and proxies internally, the process of establishing a relationship and communicating messages involves several steps. These steps are internal to the operation, but are vital to ensure that the relationship between principals cannot be faked. Horton does this all transparently, so most of the logic is in the
Horton looks pretty incredible when you first see it. The slides for Horton are a useful guide for going through the steps. I showed it to a friend, and his first reaction was to say his head hurt, he was tasting metal and seeing spots. Horton is only one of several capability patterns that use dynamic sealing as a primitive, but it's not well-known outside the ocap community.
This works with a finder from a
GreetingService contains a Gatekeeper which messes with the finder so it's only good for 5 seconds:
And then the hapless
GreetingActor has to figure out what to do with a capability once it's been revoked.
Most of what I'm doing is translating and collating information and seeing opportunities. The demo and horton are showing use cases, but I know I also have to make the case for why you would want to use object capabilities in the first place, and why you would find them useful for a business case, as opposed to "just plain cool."
One unexpected benefit of programming with capabilities is that it forces you to think about failure. Whether it's a database failure, a timeout or a revocation, you're still crossing your fingers that the data you asked for will come back to you. There's never any guarantee. But a revoked capability makes that obvious, and you can control failure to a very fine degree. You can even program failure in at precise times, under precise circumstances, or fail entire groups at once.
This isn't even getting into the cool programming language things, like stoic functions or the research being done into the correspondence between effects and capabilities, but I'm trying to keep everything as practical as I can here, so I'll leave that to others.