TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Typestates in Rust (2018)

205 pointsby lwhsiaoover 5 years ago

16 comments

cdirkxover 5 years 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.<p><pre><code> enum SenderState { ReadyToSendHello, HasSentHello, HasSentNumber, HasReceivedNumber } Sender&lt;const S: SenderState&gt; { ... } impl Sender&lt;{SenderState::ReadyToSendHello}&gt;{ ... } </code></pre> One can then give the individual states extra parameters:<p><pre><code> HasSentNumber { number: u32 } </code></pre> (Note that in this case that doesn&#x27;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.)
评论 #21416650 未加载
评论 #21415013 未加载
评论 #21417105 未加载
评论 #21417208 未加载
_hardwaregeekover 5 years ago
A good sign in a type system for me is that the types are accurately modeling behavior that I find in day to day code. To the point where moving back to a language that lacks this feature feels weirdly unsafe or not expressive enough. Going back to C APIs, with their states that need to be read via bit masks or through special integer return values, is just painful after using discriminated unions. Likewise being able to have multiple owners to a value is a little weird after using Rust.<p>Also what&#x27;s the deal with the fi ligature in the code? It throws off the kerning and holds no purpose.
评论 #21413408 未加载
评论 #21413496 未加载
frioover 5 years ago
We do something like this to encode our Redux states at compile-time (using TypeScript, obviously). Previously, using regular JS, the Redux devtools made tracking down incorrectly implemented reducers&#x2F;state transition reasonably straightforward -- but you still had to trigger a bug before you knew you had to track it down, and implement tests etc.<p>This kind of design pattern measurably saves us time; it reduces the volume of unit tests we need to write&#x2F;update when we make changes (we still test, just... with less fear), and it prevents newer developers from making mistakes. I haven&#x27;t played with Rust (beyond a couple of toy projects) yet, and articles like this remind me I&#x27;m looking forward to sinking my teeth in over the Christmas break.
评论 #21416417 未加载
评论 #21413874 未加载
dmkolobovover 5 years ago
This is one of my favorite patterns from Haskell, which I&#x27;ve known as &quot;type-level programming&quot;. One of the most common examples is a &quot;sized vector&quot;[1] which allows compile-time bounds checking. This is achieved by annotating each vector type with a phantom type variable representing its size.<p>Nice to see something like this in Rust! One thing that&#x27;s a bit of a bummer, and I&#x27;m sure there are very good reasons for this, is that we HAVE to use every type argument of struct in its definition. If this restriction were to be relaxed, we wouldn&#x27;t need the &quot;state&quot; field in the struct at all, and we could make the state type variable truly &quot;phantom&quot;.<p>[1] <a href="https:&#x2F;&#x2F;www.schoolofhaskell.com&#x2F;user&#x2F;konn&#x2F;prove-your-haskell-for-great-safety&#x2F;dependent-types-in-haskell" rel="nofollow">https:&#x2F;&#x2F;www.schoolofhaskell.com&#x2F;user&#x2F;konn&#x2F;prove-your-haskell...</a><p>EDIT: Typos.
评论 #21416667 未加载
评论 #21415275 未加载
评论 #21417056 未加载
nitnelaveover 5 years ago
I wrote something similar in C++, completely compile time that disappears at runtime: <a href="https:&#x2F;&#x2F;www.fluentcpp.com&#x2F;2019&#x2F;09&#x2F;24&#x2F;expressive-code-for-state-machines-in-cpp&#x2F;" rel="nofollow">https:&#x2F;&#x2F;www.fluentcpp.com&#x2F;2019&#x2F;09&#x2F;24&#x2F;expressive-code-for-sta...</a><p>Although the language itself doesn&#x27;t guarantee that the value is not used again after a move, good static analyzers will provide a warning in that case, so it can still be safely used.
评论 #21414564 未加载
RcouF1uZ4gsCover 5 years ago
Basically, they are using Rust to encode a state machine using types. This is brilliant! The nice thing is that the transitions are determined at compile time so there can be performance benefit as well as compile time correctness testing.<p>Really neat techniques!
评论 #21413587 未加载
reificatorover 5 years ago
Another example, implementing IMAP with Rust&#x27;s affine types.<p><a href="https:&#x2F;&#x2F;insanitybit.github.io&#x2F;2016&#x2F;05&#x2F;30&#x2F;beyond-memory-safety-with-types" rel="nofollow">https:&#x2F;&#x2F;insanitybit.github.io&#x2F;2016&#x2F;05&#x2F;30&#x2F;beyond-memory-safet...</a>
评论 #21415444 未加载
pedrowover 5 years ago
Maybe not everyone will know this but Typestate was one of the original &#x27;headline features&#x27; of Rust when Graydon Hoare started it. It was based on the Strom&#x2F;Yemeni paper[0] for the NIL language. There&#x27;s a mention of in this SO answer from 2010[1] and in the LtU discussion[2]. I&#x27;m not sure why it was de-emphasised, I think it didn&#x27;t work as well as anticipated in the &#x27;real world&#x27;<p>[0]: <a href="http:&#x2F;&#x2F;www.cs.cmu.edu&#x2F;~aldrich&#x2F;papers&#x2F;classic&#x2F;tse12-typestate.pdf" rel="nofollow">http:&#x2F;&#x2F;www.cs.cmu.edu&#x2F;~aldrich&#x2F;papers&#x2F;classic&#x2F;tse12-typestat...</a><p>[1]: <a href="https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;3210025&#x2F;what-is-typestate" rel="nofollow">https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;3210025&#x2F;what-is-typestat...</a><p>[2]: <a href="http:&#x2F;&#x2F;lambda-the-ultimate.org&#x2F;node&#x2F;4009" rel="nofollow">http:&#x2F;&#x2F;lambda-the-ultimate.org&#x2F;node&#x2F;4009</a>
dhashover 5 years ago
Scala&#x2F;Haskell has the same thing, and it&#x27;s an amazing feature. The proper type is that of<p><pre><code> trait IndexedStateT[A, B, C] </code></pre> Which signifies a typelevel state machine moving from state A to state B emitting a value of type C.<p>I can only speak for scala, but i&#x27;m assuming haskell has singleton and literal types as well. Meaning that code like this works great.<p><pre><code> object DoorOpen object DoorClosed class Door { def open: IndexedState[DoorClosed.type, DoorOpen.type, Unit] def close: IndexedState[DoorOpen.type, DoorClosed.type, Unit] } val d = Door() for { _ &lt;- d.open() &#x2F;&#x2F;works _ &lt;- d.close() &#x2F;&#x2F; works &#x2F;&#x2F; _ &lt;- d.close() &#x2F;&#x2F;compile error } </code></pre> By my understanding of the article, it uses the borrow&#x2F;move state to implement the state transistion. Is this generalizable to arbitrary state machines, or only a simple 2-state one?
评论 #21415761 未加载
unlinked_dllover 5 years ago
This is a really useful pattern when you want to have rigidly defined&#x2F;enforced state transitions to ensure that the data is never in an invalid state for a given operation.<p>It&#x27;s pretty awful to deal with when you&#x27;re unsure of what the state machine should look like, or if there needs to be a lot more flexibility in how the data is accessed. Maintainability nightmare.<p>An example of this I ran into is a data processing pipeline architecture where each vertex of the processing graph had a processing function called in a loop on its own dedicated thread. Using the type state pattern helped clearly define the &quot;life cycle&quot; of each vertex and enforce it, which provided for some powerful synchronization guarantees (e.g. we could provide <i>some</i> elements of memory safety even when loading things through shared libraries). If you dug into it you could break things, but that would be more work than just following the pattern.
gameswithgoover 5 years ago
Are there other languages that can do the trick done with &quot;close()&quot; on the file there? A type with a method that can make the type compile time unusable after being called!<p>that is pretty neat.
评论 #21414929 未加载
评论 #21415318 未加载
评论 #21416311 未加载
评论 #21414535 未加载
评论 #21417418 未加载
amedvednikovover 5 years ago
&gt; 2. we have seeked in a file that was already closed.<p>&gt; The second error, however, is much harder to catch. Most programming languages support the necessary features to make this error hard, typically by closing the file upon destruction or at the end of a higher-order function call, but the only non-academic language that I know of that can actually entirely prevent that error is Rust.<p>Why not simply add an `is_closed` flag and throw an error if it is?
评论 #21417260 未加载
评论 #21417406 未加载
justryryover 5 years ago
This is one my favorite features of the language and I believe to be fairly unique. It can make for some slick and safe state machine like code.<p>I do wish that we had reliable RVO so that this could come at zero cost.
nixpulvisover 5 years ago
<a href="https:&#x2F;&#x2F;github.com&#x2F;Munksgaard&#x2F;session-types" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;Munksgaard&#x2F;session-types</a>
jbrittonover 5 years ago
This line caught my eye.<p>my_file.open(); &#x2F;&#x2F; Error: this may fail.<p>1) If this can fail, then it should be a compile error to not test the result code.<p>2) IMHO it would be nice if there was something like Python&#x27;s with statement to correctly close a file.<p><pre><code> with open(filename, &#x27;r&#x27;) as f: f.read() # f.close() invoked automatically here </code></pre> This prevents trying to close a file that is not opened.<p>The idea of encoding a state machine into the types seems interesting.
评论 #21413763 未加载
评论 #21413771 未加载
评论 #21414501 未加载
评论 #21413750 未加载
评论 #21414125 未加载
评论 #21415522 未加载
评论 #21414669 未加载
评论 #21413828 未加载
评论 #21414013 未加载
caleb-allenover 5 years ago
Feels similar to Kotlin&#x27;s sealed classes
评论 #21413817 未加载
评论 #21413633 未加载