Re:State Machines and the Strange Case of Mutating API
by sriram_malhar on Monday December 24, 2018 @06:52AM
(#18751718)
This is precisely the problem addressed by typestates and session types. Each state has a unique type, and in that state, one can only call the appropriate functions.
Re:State Machines and the Strange Case of Mutating API
by Sharlin on Monday December 24, 2018 @05:01PM
(#18754500)
Rust's affine typing solves precisely this problem as well. Your state change methods consume the previous state variable, making it a compile-time error to access it afterwards. Given code like in the article and assuming connect_unauthenticated takes self by value:
let i1 = socks5_socket();
let i2 = i1.connect_unauthenticated(proxy_addr);
let i3 = i1.connect_tcp(addr);
Rust will complain:
error[E0382]: use of moved value: `i1`
|
2 | let i2 = i1.connect_unauthenticated(proxy_addr);
| - value moved here
3 | let i3 = i1.connect_tcp(addr);
| ^ value used here after move
|
= note: move occurs because `i1` has type `socks5_socket`, which does not implement the `Copy` trait
Re:State Machines and the Strange Case of Mutating API
by sriram_malhar on Tuesday December 25, 2018 @10:01AM
(#18757636)
Yes, between traits and alias control, you have everything required to solve OP's problem safely and efficiently. The only remaining aspect, I feel, is aesthetic, as the errors show; they show aliasing/ownership errors, but not indicative of operations on a single state machine.
Rust adds the constraint that any (non-copyable,non-dropable) variable has to be passed to a function (or operator, or return statement) exactly once:
Noncopyable a = ...;
Copyable b = ...;
f(a,b); //=> f(a,copy(&b)) // a is no longer in scope after this
g(b); // this is fine, we took a reference to b and made a copy without changing the original
h(a); // error: a is no longer a live variable
Re:State Machines and the Strange Case of Mutating API
by a1369209993 on Tuesday December 25, 2018 @01:45PM
(#18758663)
Er, yes; that's what I said (or rather, hanging various things including but not limited to pointers). C only supported the typechecking part of this because it doesn't have any facilities for compile-time linearity checking.
Linearity[0] and dependency[1] checking is what makes Rust a improvement over C, rather than yet another "let's reinvent C++, but slightly less awful" project.
0: "error: no implementation for copy〈T〉","error: no implementation for drop〈T〉"[2]
1: "error: cannot move/destroy x (of type T); y (of type T&'x) outlives it"
Re:State Machines and the Strange Case of Mutating API
by geezerjay on Tuesday December 25, 2018 @04:11AM
(#18756680)
> What is wrong with implementing the states with polymorphic classes providing the API or an interface to it?
Yeah that's pretty much the basic approach to this problem: use a strategy pattern in all states of the state machine, and just provide definitions for each method in the state that the method makes sense.
That's pretty much how HTTP-based protocols are implemented when status codes drive a state machine.
I wonder why the author decided to ignore the most basic and simple solutions to a frequent problem in favour of a convoluted solution that doesn't add anything and is harder to debug.
Interestingly, Rust used to have typestates in its very early incarnation. See: https://pcwalton.github.io/2012/12/26/typestate-is-dead.html
That new wizkid language Zig by Andrew Kelly - I wonder if it has anything similar?
Linearity[0] and dependency[1] checking is what makes Rust a improvement over C, rather than yet another "let's reinvent C++, but slightly less awful" project.
0: "error: no implementation for copy〈T〉","error: no implementation for drop〈T〉"[2]
1: "error: cannot move/destroy x (of type T); y (of type T&'x) outlives it"
What is wrong with implementing the states with polymorphic classes providing the API or an interface to it?
Yeah that's pretty much the basic approach to this problem: use a strategy pattern in all states of the state machine, and just provide definitions for each method in the state that the method makes sense.
That's pretty much how HTTP-based protocols are implemented when status codes drive a state machine.
I wonder why the author decided to ignore the most basic and simple solutions to a frequent problem in favour of a convoluted solution that doesn't add anything and is harder to debug.
https://developer.apple.com/library/archive/documentation/Ge...