Functional programs are easy to write, but programs that interact with each other and the outside world are much harder.
Programming models like the Actor model and the Tuplespace model make great strides toward simplifying programs that communicate. However, a few key difficulties remain.
The Syndicated Actor model addresses these difficulties. It is closely related to both Actors and Tuplespaces, but builds on a different underlying primitive: eventually-consistent replication of state among actors. Its design also draws on widely deployed but informal ideas like publish/subscribe messaging.
Cool stuff. One of the genode contributors seemed to be into this project for a bit (maybe still is?)
It seems like there’s definitely something there, but I confess it’s a little over my head what exactly the use cases are intended to be.
Genode IPC would be a good use case for Syndicate. Higher-level Genode IPC tends to be mostly asychronous and involves components sharing state as XML documents. It’s fast, it’s simple to implement, and it works for them. However, in my opinion, it has its limits.
These XML state documents tend to lack normative schema.
Exposing a subset of an XML doc to a third party via a capability is not possible without allocating an additional Genode dataspace and a transformation using something like XPATH and XSLT (and linking to libxslt+libc).
There is no blessed method of tunnelling the Report/ROM transactions over network (that I know of).
Communicating with other OSes requires another protocol.
Genode capabilities are not embeddable in XML.
These are things that Syndicate can do. Syndicate uses the Preserves language that is effectively a superset of what XML offers.
Preserves has schema and code generators. Protocols built on Syndicate are defined with schema as well as the Syndicate protocol itself.
Syndicate can attenuate capabilities to filter and transform the documents that are relayed thru them.
Syndicate can be tunneled over network, and tunneled recursively within itself.
Syndicate protocol is OS agnostic.
The Syndicate protocol is capability based and the Preserves language can embed capabilities. Genode session capabilties obviously aren’t usable on a remote machines, but transfering a Genode cap from one component to a different host, then back again to a different component on the original host is possible and a useful thing to do.
A Genode port would be possible but more complicated than Report+ROM+XML. Although I think its a bargain compared to strapping together other protocols to achieve the same features. Syndicate would not replace lower-level Genode IPC as you still need synchronous IPC to transmit capabilties and a packet session to carry Syndicate protocol.
That’s very interesting, I was thinking along the same lines that Capn’Proto would be a useful high-level format to complement or replace the XML.
Going to go through in more detail the differences later tonight, but it seems like the main thing is that Syndicated Actors have an eventually consistent model with automatic resubscribing and state transfer, while CapnP is direct RPC.
I think so. I believe CapnP is is not self-describing, whereas Preserves is, and I think in the case of Genode a self-describing format is ideal because state and configuration documents can be interchangeable, and this is a means of malleability.
The “eventually consistent” bit makes transfering Genode capabilities complicated because delegating and revokeing capabilities must be done using synchronous Genode IPC and this could invalidate in-flight embedded caps. It would still be interesting to try.
I had totally forgotten about Syndicated Actor Model. @leastfixedpoint is such a mensch. This was super fun to run into again!! It’s awesome to see some activity in the repos. Great share, thanks.
This is such a wonderful agentful practice. There’s so much good concept building here. The introduction of facets really resounds;
To address these requirements, Syndicate represents conversations with a language construct called a facet. Facets are similar to the “nested threads” of Martin Sústrik’s idea of Structured Concurrency (see also Wikipedia).
Every actor has at least one (root) facet, and all its facets form a tree. Generally speaking, one facet corresponds to one conversation, framing (in the sense of Conversational Concurrency) its children, which each correspond to some *sub-*conversation within the frame of their parent.
When a parent facet is shut down, all its children are shut down in an orderly fashion, making management of conversational state straightforward.
Each facet publishes (“asserts”) relevant pieces of state (“assertions”) to relevant peers. As its internal state changes, its published assertions are re-evaluated, and any changes are automatically propagated to peers.
Facets also subscribe to assertions emanating from their peers. They do this in a unique way: by asserting their interest in particular fact(s) to the publishing peer. That is, an expression of interest is itself an assertion that can be seen and reacted to by peers.
The conversational state that accumulates as part of a collaboration among components can be thought of as a collection of facts. First, there are those facts that define the frame of a conversation. These are exactly the facts that identify the task at hand; we label them “framing knowledge”, and taken together, they are the “conversational frame” for the conversation whose purpose is completion of a particular shared task.