[−][src]Type Definition dialectic::Chan
type Chan<Tx, Rx, P, E = ()> = CanonicalChan<Tx, Rx, <P as Actionable<E>>::Action, <P as Actionable<E>>::Env>;
A bidirectional communications channel using the session type P
over the connections Tx
and
Rx
.
See the documentation for CanonicalChan
for available methods and trait
implementations.
Important: always write this type synonym (Chan
) in type signatures, not️
CanonicalChan
directly. This is because the Chan
type synonym canonicalizes its
session type argument, which means it can be used more flexibly. The details:
Technical notes on canonicity: TL;DR: always write Chan
In Dialectic, operations are liberally available on Chan
s wherever they make
sense. For instance, it's valid to call send
on a channel which was
created using the session type Loop<Send<String>>
, even though the type does not literally
begin with Send<String>
.
A CanonicalChan
always has a session type which is syntactically a real action: it will never
be Loop
, Continue
, or Break
(or, when inside a Loop
, it will never be Done
).
Every action available on a CanonicalChan
"fast-forwards" through such control operators,
yielding a CanonicalChan
that corresponds to the next real action available.
While this design means greater flexibility and concision in writing session-typed code, it can
be confusing in the case where you want to explicitly write out the session type of a channel,
because the automatic canonicalization can mean a Chan
does not have the type
you might think it does.
⚠️ The problem: Suppose you wanted to explicitly annotate the type of a new channel:
use dialectic::canonical::CanonicalChan; type P = Loop<Send<String>>; let (c1, c2): (CanonicalChan<_, _, P, ()>, _) = P::channel(mpsc::unbounded_channel);
This fails to typecheck, returning several errors (abridged for clarity):
error[E0271]: type mismatch resolving `<Loop<Send<String>> as Actionable>::Action == Loop<Send<String>>`
= note: expected struct `Loop<Send<_>>`
found struct `Send<_>`
error[E0271]: type mismatch resolving `<Loop<Send<String>> as Actionable>::Env == ()`
= note: expected unit type `()`
found type `(Send<String>, ())`
These errors indicate that the returned CanonicalChan
from P::channel
does not have the
session type P
and the initial empty environment E = ()
, as annotated. Instead, it has the
session type and environment corresponding to the inside of the Loop
, which are the
canonical session type and environment for P
.
💡 Do this instead: When annotating the types of channels, prefer the type synonym
Chan
, which computes the correct CanonicalChan
type for a given (possibly
non-canonical) session type. Using Chan
instead of CanonicalChan
, we can
correctly annotate a newly created channel of any session type:
type P = Loop<Send<String>>; let (c1, c2): (Chan<_, _, P>, Chan<_, _, <P as Session>::Dual>) = P::channel(mpsc::unbounded_channel);