Cliff Biffle
cliffle.com · Personal blog · on HN since 2019
Cliff Biffle writes about Rust, embedded systems, and operating system design, including the Hubris OS.
What HN saysCommenters recommend his series on learning Rust from a C perspective and his posts on the typestate pattern and Hubris.
81HN people shared it
46linked it in comments
53stories submitted
2.2Kstory points
3 months agolast shared
2019people per year2026
Most-shared posts
- 1The Typestate Pattern in Rust (2019)22 people · 15 points · first shared 2019 · 1 comments on HN
- 2Learn Rust the Dangerous Way14 people · 356 points · first shared 2019 · 23 comments on HN
- 3Bare Metal WASM7 people · 6 points · first shared 2020 · 1 comments on HN
- 4The server chose violence6 people · 322 points · first shared 2024 · 62 comments on HN
- 5Prefer Rust to C/C++ for new code6 people · 21 points · first shared 2019 · 8 comments on HN
- 6On Hubris and Humility5 people · 105 points · first shared 2021 · 27 comments on HN
- 7How to think about `async`/`await` in Rust4 people · 3 points · first shared 2023 · discussion on HN
- 8Rewriting m4vgalib in Rust3 people · 383 points · first shared 2020 · 44 comments on HN
- 9Let the Compiler Do the Work3 people · 213 points · first shared 2020 · 60 comments on HN
- 10Why Rust mutexes look like they do3 people · 37 points · first shared 2022 · 16 comments on HN
- 11Making My Website Faster3 people · 10 points · first shared 2024 · 1 comments on HN
- 12Async Rust Debugger3 people · 5 points · first shared 2023 · discussion on HN
- 13The HQ9 Programming Language (2001)3 people · 4 points · first shared 2021 · discussion on HN
- 14Crash Recovery in 256 Bytes3 people · 4 points · first shared 2024 · discussion on HN
- 15Who killed the network switch? A Hubris Bug Story2 people · 363 points · first shared 2024 · 128 comments on HN
What HN people wrote when they linked it
BD103 · 2023-10-26
I follow a person on Github who works here! (cbiffle[0]) They wrote a fantastic series[1] on learning Rust from a C perspective and I highly recommend it.
[0]: https://github.com/cbiffle
[1]: https://cliffle.com/p/dangerust/
herbstein · 2023-02-14
> There is a lot of C++ code out there. A lot of it was not written by people who understand performance or who care. It is very easy to take that kind of code and make it faster, even without a switch to Rust.
Cliff Biffle's great series of blog posts called "Learn Rust the Dangerous Way" takes the fastest C program from a benchmark game entry, rewrites it naïvely in Rust using copious amounts of `unsafe`, and then transforms it into program without `unsafe` while keeping it idiomatic. The last version is faster than the C implementation.
It's a toy example but it's real-world example.
http://cliffle.com/p/dangerust/
the__alchemist · 2022-06-03
I was implicitly referring to [Typestates](http://cliffle.com/blog/rust-typestate/) as an example; the details will depend on which generic patterns are used. I like the advantage they provide by catching incorrectly-configured hardware, but in practice, I don't think they're worth the application-side code complexity and learning curve vice using simpler APIs.
bcantrill · 2022-03-23
Interesting! I (obviously?) hold Bunnie's work in very high regard, but I had not seen Xous before. It seems to be similar in some respects to Hubris[0], but it's hard to discern its design center as most of the documentation appears to be forthcoming? Regardless, it's great to see more work in this important domain!
[0] http://cliffle.com/blog/on-hubris-and-humility/
bogeholm · 2021-07-24
Here’s a blog series about rewriting some classic C in Rust, first unsafely and then safely, and getting some performance wins along the way: http://cliffle.com/p/dangerust/
neopallium · 2021-01-04
Someone wrote a 6 part of blog post [0] about porting that nbody benchmark from C to Rust. They went from a straight line by line port using unsafe rust using the same SSE based design to clean no-unsafe and no SSE rust code that was faster then the original C code with hand optimized SSE.
It is a great example of how the Rust compiler can auto-vectorize code.
0. http://cliffle.com/p/dangerust/6/
unlinked_dll · 2020-04-01
I disagree with the implementation, State should be a trait with NextState as an associated type. This makes things cumbersome when it can be a set of types, but it makes excellent use of the type system and ownership patterns of Rust. Edit: and the type state pattern http://cliffle.com/blog/rust-typestate/
As an aside, if you want to dive in with FSMs and automata theory (as well as some basic language topics) go read Sipser's book, "Introduction to the Theory of Computation." You'll go from logic to state machines to understanding why Turing Machines are so dope in a few dozen pages. The math isn't bad.
masklinn · 2020-01-07
> What is the realistic best-case scenario?
Finding latent logic and memory errors, gaining greater confidence, security and velocity.
> Has anyone demonstrated that well-written Rust code should run faster than C
Should? No. Can? Yes. See Brian Cantrill’s http://dtrace.org/blogs/bmc/2018/09/28/the-relative-performance-of-c-a… or Cliff Biffle’s http://cliffle.com/p/dangerust/
aw1621107 · 2026-01-08
> I'd argue, that while null ref and those classes of bugs may decrease, logic errors will increase.
To some extent that argument only makes sense; if you can find a way to greatly reduce the incidence of non-logic bugs while not addressing other bugs then of course logic bugs would make up a greater proportion of what remains.
I think it's also worth considering the fact that while Rust doesn't guarantee that it'll catch all logic bugs, it (like other languages with more "advanced" type systems) gives you tools to construct systems that can catch certain kinds of logic bugs. For example, you can write lock types in a way that guarantees at compile time that you'll take locks in the correct order, avoiding deadlocks [0]. Another example is the typestate pattern [1], which can encode state machine transitions in the type system to ensure that invalid transitions and/or operations on invalid states are caught at compile time.
These, in turn, can lead to higher-order benefits as offloading some checks to the compiler means you can devote more attention to things the compiler can't check (though to be fair this does seem to be more variable among different programmers).
> Rust is not an extraordinary readable language in my opinion, especially in the kernel where the kernel has its own data structures.
The above notwithstanding, I'd imagine it's possible to think up scenarios where Rust would make some logic bugs more visible and others less so; only time will tell which…
rstuart4133 · 2025-09-23
> The Rust community should be upfront about this tradeoff - it's a universal tradeoff, that is: Safety is less ergonomic.
That can be true for small programs. Not always, because Rust's type system makes for programs that can be every bit as compact as Python if the algorithm doesn't interact badly with the borrow checker. Or even if it does. For example this tutorial converts a fairly nary C program to Rust: https://cliffle.com/p/dangerust/ The C was 234 lines, the finished memory safe Rust 198 lines.
But when it comes to large programs, the ergonomics strangely tips into reverse. By "strangely tips into reverse", I mean yes it takes more tokens and thinking to produce a working Rust program, but overall it saves time. Here a "large program" means a programmer can't fit it all in his head at one time. I think Andrew Huang summed the effect up best, when he said if you start pulling on a thread in a Rust program, you always get to the end. In other languages, you often just make the knot tighter.
diarrhea · 2023-09-22
This is good, but could go further if you're pursuing type-system leverage. For example, why does a deleted user have an `activate` associated function in the first place? It will error out! That's safe in Rust and perfectly fine in terms of control flow: it cannot be forgotten, and cannot easily be handled incorrectly (unlike, say, a bool, where a single exclamation mark can mean a nasty bug). But it's not ideal.
I've been a huge fan of the type-state pattern [1]. I don't see it mentioned often, and never outside of Rust so far. However, it's applicable to most languages, including ones you wouldn't suspect (Python). If you introduce a whole new type (not a big deal in Rust; more of a ceremony in C# et al.) for `DeletedUser`, you can simply leave off the `active` function! Any action (==state transition) on that type will be legal and possible. Methods have unit value return type, no `Result` needed. You cannot handle that incorrectly! The code won't even compile.
I am still in the process of exploring downsides to the pattern. For example, in classic OOP languages, you can create a type hierarchy, with a top-level `User`, and the different kinds inheriting from it (and then ideally be marked `final`/`sealed` or whatever). You can then treat all users the same by interacting with the top-level type. Useful for DB interaction, for example. The same in Rust would go through traits: `impl User for DeletedUser`. But it's not quite as nice, is it?
1:…
gary17the · 2022-11-08
> First off types can't emmit values. Types don't exist at run time.
Incorrect. Please have a look at OpenCombine sources, or, say, at the Typestate Pattern in Rust:
http://cliffle.com/blog/rust-typestate/
"Typestates are a technique for moving properties of state (the dynamic information a program is processing) into the type level (the static world that the compiler can check ahead-of-time)."
> you're completely ignorant about type theory. (...) This is just fucking rude. (...) I didn't realize how stupid and rude people can actually be.
Yes, of course, naturally, you must be right, how blind could I have been?
> I'd appreciate an apology if you had any gall.
Sure, sorry about my little previous joke[1], meant no factual offense. The very best of luck to you as a programmer and a wonderfully polite human being with a great sense of humor.
[1] "Topper: I thought I saw Elvis. Block: Let it go, Topper. The King is gone. Let's head for home." ("Hot Shots!", 1991)
nyanpasu64 · 2022-06-03
Rust marks cross-thread shared memory as immutable in the general case, and allows you to define your own shared mutability constructs out of primitives like mutexes, atomics, and UnsafeCell. As a result you don't get rope to hang yourself with by default, but atomic orderings are more than enough rope to devise incorrect synchronizations (especially with more than 2 threads or memory locations). To quote an earlier post of mine:
In terms of shared-memory threading concurrency, Send and Sync, and the distinction between &T and &Mutex<T> and &mut T, were a revelation when I first learned them. It was a principled approach to shared-memory threading, with Send/Sync banning nearly all of the confusing and buggy entangled-state codebases I've seen and continue to see in C++ (much to my frustration and exasperation), and &Mutex<T> providing a cleaner alternative design (there's an excellent article on its design at http://cliffle.com/blog/rust-mutexes/).
My favorite simple concurrent data structure is https://docs.rs/triple_buffer/latest/triple_buffer/struct.TripleBuffer… It beautifully demonstrates how you can achieve principled shared mutability, by defining two "handle" types (living on different threads), each carrying thread-local state (not TLS) and a pointer to shared memory, and only allowing each handle to access shared memory in a particular way. This statically prevents one thread from calling a method intended to run on another thread, or accessing fields local…
ssokolow · 2022-06-03
Not really.
For me, the number-one Rust feature I love is that, by baking monadic optionality and error return in from the beginning (Option<T> and Result<T, E>), I can trust that, unless an author abuses panic! (in which case I never trust their code again), I can see all a function's return paths in its type signature. (Without having to choke down a pure functional language like Haskell with that currying-based function call syntax that I can never get used to.)
The runners-up are how fast Rust starts compared to Python or Java or similar when writing a CLI tool and how nice PyO3 makes safely writing libraries or backends for tools that need to be in Python for some reason like "nothing but PyQt, PySide and possibly QtJambi offers memory-safe QWidget bindings... and I've never found a Java app that didn't feel laggy and sluggish on X11".
See also https://cliffle.com/blog/rust-typestate/
afdbcreid · 2026-07-25
I absolutely agree learning C is a good thing! In fact, there are two camps of Rust people: one that argue that you should not learn C before learning Rust, and one that argues that you should.
Also, while such data structures/algorithms are rare, and more importantly, they can be written once and used many times, someone still needs to write them!
Here is some online content on this side of Rust:
- Learn Rust the Dangerous Way - https://cliffle.com/p/dangerust/
- Learn Rust With Entirely Too Many Linked Lists - https://rust-unofficial.github.io/too-many-lists/
- The Rustonomicon - https://doc.rust-lang.org/nomicon/
jrpelkonen · 2025-11-28
The typestate pattern common in Rust applications allows the compiler to verify that the operations are executed in the right order and that previous states are not accidentally referenced. Here’s a good description: https://cliffle.com/blog/rust-typestate/
astahlx · 2025-06-23
How would you compare it to Rust Type States, for example: https://cliffle.com/blog/rust-typestate/ ?
wging · 2025-04-20
I think I first learned of that term from this 2019 article: https://cliffle.com/blog/rust-typestate/ I can't be the only one...
p_l · 2025-02-12
As sibling comments mentioned, someone's you want to enforce things.
Also consider it a way to avoid hidden bugs, similar to "The server chose violence" [1] [2] as well as how much Postel's law held back interoperability (which is forgotten by many aspect of FIPS certifications)
[1] https://cliffle.com/blog/hubris-reply-fault/
[2] https://news.ycombinator.com/item?id=40178652
FFFXXX · 2024-10-21
The 95% safe Rust Code does not use any auto-vectorization (https://cliffle.com/p/dangerust/5/nbody-5.rs)
Only the 100% Rust-safe implementation uses auto-vectorization and is at 0.73% of the RUNTIME of the C code. (https://cliffle.com/p/dangerust/6/#performance-evaluation)
smokel · 2024-10-06
The built-in functions and API to a system library spoil these metrics. As an example, consider HQ9+, which is pretty good at printing "Hello, world!" for instance.
https://cliffle.com/esoterica/hq9plus/
scns · 2023-11-16
> The "enforce preconditions via types" is a common pattern in Rust
Called the Type State Pattern. Here are two links from my bookmarks:
https://cliffle.com/blog/rust-typestate/
https://yoric.github.io/post/rust-typestate/
trealira · 2023-10-26
It will work if you only use raw pointers everywhere, like it's C. Don't use slices or strings; just pass a pointer to the first element of an array, and either pass its length separately or provide a sentinel value (like C's null terminated strings). Navigate balanced search trees using aliasing, raw, mutable pointers. Etc. This person compares the translation of C to Rust, literally versus idiomatically: https://cliffle.com/p/dangerust/
There will probably be weird behavior, though, because Rust optimizes based on assumptions about boxes and references. For example, if you have 3 raw pointers to some object live at once, and you give some library function a mutable reference made from one of those pointers, the compiler will optimize assuming it has exclusive access to that object, and it may make incorrect assumptions.
andsoitis · 2023-08-19
> It clearly states: it targets web assembly. So, this should answer your question I think
Not sure what you're implying.
Here's an example of doing graphics using Rust and WASM - http://cliffle.com/blog/bare-metal-wasm/#making-some-pixels
And another: https://blog.logrocket.com/implement-webassembly-webgl-viewer-using-ru…
Given that MoonBit is developing their own IDE and it is hosted on the web, I would think one could provide an elegant pipeline to do graphics programming, no?
If this were open source, I would contribute in this realm becase I'm a graphics and UI person and also enjoy working with new programming languages.
sitkack · 2023-07-02
pkolaczk · 2023-02-14
This series of posts disagrees: http://cliffle.com/p/dangerust/1/
Spoiler: the end result uses idiomatic Rust, doesn't use unsafe and is faster than the hand-optimized version in C (and hand optimized one in Rust).
nextaccountic · 2022-12-01
That's true! It's not an "also", you use both linear/affine types plus the typestate pattern
For the curious, it works like this in Rust http://cliffle.com/blog/rust-typestate/ https://willcrichton.net/rust-api-type-patterns/typestate.html
Or rather, typestate itself needs either linear/affine types or a similar mechanism to make sure that when you are in the "closed" state you can't access methods from the "open" state, and vice-versa. (now, there are languages that implement typestate as a language feature rather than a design pattern, but I don't know how they work)
the_mungler · 2022-11-23
To be fair, rust at kernel level seems to have way more unsafe code than usual, though I have no experience in that area so I can't say much.
In rust you absolutely can "just take a lock around some shared data", but it is a bit different then other languages. mutexes actually contain the data they guard, making it impossible to modify unless you have the lock. There is another article about muexes by this same author if you want more details: http://cliffle.com/blog/rust-mutexes/
nfrmatk · 2022-09-17
In case you haven't seen it already, Cliff Biffle's "Learn Rust the Dangerous Way" might be of interest to you.
https://cliffle.com/p/dangerust/
dureuill · 2022-02-19
In general, I think they should go for Rust. See [1].
Now, embedded is a special case. You need platform support, and possibly certification, none of which are a given in Rust today. Arguably, not in C23 either at the moment, though.
[1]: http://cliffle.com/blog/prefer-rust/