3 ms·
When const generics are fully implemented (they are partially usable on nightly rust now) this will enable an even stronger version of this pattern, allowing yo
by cdirkx 7y ago
When const generics are fully implemented (they are partially usable on nightly rust now) this will enable an even stronger version of this pattern, allowing you the full power of enums to represent the state.
enum SenderState {
ReadyToSendHello,
HasSentHello,
HasSentNumber,
HasReceivedNumber
}
Sender<const S: SenderState> {
...
}
impl Sender<{SenderState::ReadyToSendHello}>{
...
}
One can then give the individual states extra parameters:
HasSentNumber {
number: u32
}
(Note that in this case that doesn't make much sense, the number that is sent is more associated data then an actual type parameter. There is no real difference, at the type level, between HasSentNumber { number: 3 } and HasSentNumber { number: 6 }, and the compiler generating two types for this would be unnecessary. It is only an example of the syntax.)
- cdirkx 7y agoRe: associated data for a state, that's possible too! trait StateData { type Data; } struct Sender<const S: SenderState> { ... // sender implementation state_data: <Self as StateData>::Data } impl<const S: SenderState> StateData for Sender<{S}> { // default: no associated data default type Data = (); } struct HasSentNumberData { sent: u32 } // using a specialized impl (also an unstable feature). impl StateData for Sender<{SenderState::HasSentNumber}> { // instead of a complete struct we could also have done Data = u32, // but a separate struct would enable a nicer constructor, default values, helper methods and so on. // (ommitted in this example though) type Data = HasSentNumberData; } struct HasReceivedNumberData { sent: u32, received: u32 } impl StateData for Sender<{SenderState::HasReceivedNumber}> { type Data = HasReceivedNumberData; } Example usage: impl Sender<{SenderState::HasReceivedNumber}> { ... fn validate_received_number(&self) -> bool { self.state_data.received == self.state_data.sent } } let sender = Sender::<{SenderState::HasReceivedNumber}> { state_data: HasReceivedNumberData { sent: 3, received: 28 } }; assert_eq!(sender.validate_received_number() == false) // client sent wrong number! Playground link to see this in action: https://play.rust-lang.org/?version=nightly&mode=release&edition=2018&gist=81ee6b0f97b214b59fe1d08259c88ee8 https://play.rust-lang.org/?version=nightly&mode=release&edi...
- oleganza 7y agoYou can do session types already in stable Rust without const generics. Each "enum variant" can be its own separate type, and such types can only be instantiated by a method on the type representing the previous state, which also consumes that previous state. We've used them in our Bulletproofs MPC (multi-party computation) where cryptographic requirement is not to replay the protocol from the mid-point. Since the user is supposed to perform these transitions within their application on top of network messages, such strongly-typed API guarantees that, if their program has compiled successfully, then: 1) Steps are performed in correct order. 2) The protocol cannot be replayed from the intermediate state. We have wrote about it here: https://medium.com/interstellar/bulletproofs-pre-release-fcb1feb36d4b https://medium.com/interstellar/bulletproofs-pre-release-fcb... - scroll to "strongly-typed multiparty computation".
- oleganza 7y agoHere is updated link to the original article on MPC by Cathie Yun: https://medium.com/@cathieyun/bulletproof-multi-party-computation-in-rust-with-session-types-b3da6e928d5d https://medium.com/@cathieyun/bulletproof-multi-party-comput...
- Munksgaard 7y agoAs others have mentioned, and as the post itself also was updated to say, you don't need const generics to support this pattern: https://github.com/Munksgaard/session-types https://github.com/Munksgaard/session-types, http://munksgaard.me/papers/laumann-munksgaard-larsen.pdf http://munksgaard.me/papers/laumann-munksgaard-larsen.pdf
- cdirkx 7y agoYes you don't need const generics, after all that is what the entire post is about. I was merely offering a perspective on how the const generics might offer an alternative way to express the same ideas, and possibly change the idiomatic way to write them. Type level values, especially enums, IMHO offer an intuitive way to encode what is going on.
- dingoegret 7y agoIf rather just have enum variants as dedicated types.