Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync session #11

Open
ebfull opened this issue Oct 25, 2015 · 3 comments
Open

Sync session #11

ebfull opened this issue Oct 25, 2015 · 3 comments

Comments

@ebfull
Copy link
Owner

ebfull commented Oct 25, 2015

In some kinds of protocols (for example, relay networks) it may make sense for both sides of the transmission to be capable of sending to the other side. However, in our library it is only possible for one side to send to the other at any given time.

We either need a new session type that allows both sides to send a message at the same time, or a rethink of the design to perhaps anticipate two channels.

@ebfull
Copy link
Owner Author

ebfull commented Oct 25, 2015

Design 1

In Sync<P, Q>, you can transition to P by sending a discriminant over the channel and transitioning to Latent<P>. After you receive a discriminant back, regardless of what you receive, you transition to P immediately. Latent will allow you to send but not to receive. The degenerate case, transitioning to Q, transitions you to Proposed<P, Q> and in the mean time sends a discriminant. If you're in this session you transition to either P or Q as instructed.

This allows only one party to begin sending immediately through P. However, transitioning to Q requires full negotiation.

This is insufficient for our needs but still interesting.

@ebfull
Copy link
Owner Author

ebfull commented Oct 26, 2015

Design 2

Duplex<((), P), ((), Q)> is a session that allows two protocols to be interacted with concurrently. The Duplex holds the environment for both sessions. Either side can immediately send on either protocol, transitioning into the respective new one, by attaching a discriminant to the beginning of their message which indicates the target protocol. This achieves our goal of concurrent communication.

The implementation details are the most interesting part.

  • If you must send a discriminant alongside every message, even when it (might?) be unambiguous which protocol it is intended for, it could be inefficient. Perhaps there is a way to compromise, with a special session type even?
  • It should be possible to "pack" a choose() over either one of these protocols into the same byte or bytes preceeding the message.
  • How could both sides of the channel negotiate to "escape" from the duplex?
  • How would nested a Duplex function? There would have to be some sort of intermediate state to keep track of the fact that the discriminant hasn't been sent, or has been sent...

@ebfull
Copy link
Owner Author

ebfull commented Oct 26, 2015

Design 2: Take 2


Duplex<S, Q> is a session type which allows both S and Q to be interacted over concurrently via a single channel. Its Dual is Duplex<S::Dual, Q::Dual>. However, Nest/Escape is prohibited within this to avoid the need to deal with environments early on in this design.

The core principle is that you can select either protocol and immediately act through it if we're expected to Send or Choose with it. We can abstract this away using some form of Writer session type. .select1() on a Duplex<S, Q> will return a Writer<S, ((), Q)> after sending a discriminant over the channel, which will allow you to perform an operation such as .send(T) if S were Send<T, R>, returning a Duplex<R, Q>. .select2() acts differently but as you'd expect.

Recv/Accept is different, because you cannot selectively receive on either protocol without a buffer, which would defeat the purpose. So, you must .obtain() on the Duplex<S, Q> to attempt to read a discriminant from the channel. If it succeeds, it will either call your handler for Reader<S, ((), Q)> or Reader<Q, (S, ())>. With this, you can .recv() or .accept() as you desire, which will transform this back into the appropriate Duplex.

Remaining concerns
  1. How should we escape from Duplex sessions? Resolved: Duplex<S, Q, F> where .exit() is defined over Duplex<End, End, F> which returns F.
  2. It'd be nice if session types could implement things like .send() over themselves instead... Not possible.
  3. I need to form a trait heirarchy for session types to prohibit or permit certain compositions, both for coherence purposes and for safety reasons (as above).
  4. If we could prove to the compiler that it's impossible, under any scenario, for the opposite end of the channel to be in Recv without an interaction from us, we could avoid a discriminant in many situations. (The discriminant should only serve as a disambiguation when neceessary.) Resolved using barriers (will explain later).
  5. It still should be possible, somehow, to "compress" the discriminant of a .select1().choose() into a single byte.
  6. How should we handle "closing" channels? And "waiting" operations? *update: * Never .defer() on an End.
  7. How should we anticipate "waking" up channels for async purposes? As an example, in a relay network, one peer will send us data that we need to broadcast to all of the other peers. However, our channels will be "asleep" until mio or something else wakes it up. I need to prototype something running on nemo to fully understand the library design before I start adding crazy features like Duplex...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant