boats
boats.gitlab.io · Personal blog · on HN since 2017
boats (withoutboats) is a Rust contributor who writes about language design, async/await, effects, error handling, and io-uring.
What HN saysHN commenters recommend his posts, such as Zero Cost Abstractions and the explicitness essay, and cite his work when discussing Rust design choices and error crates.
71HN people shared it
36linked it in comments
49stories submitted
1.9Kstory points
9 months agolast shared
2017people per year2026
Most-shared posts
- 1Not Explicit7 people · 158 points · first shared 2017 · 32 comments on HN
- 2Garbage collection as a Rust library7 people · 16 points · first shared 2018 · discussion on HN
- 3Notes on a Smaller Rust6 people · 106 points · first shared 2019 · 116 comments on HN
- 4Zero Cost Abstractions5 people · 350 points · first shared 2019 · 110 comments on HN
- 5The problem of effects in Rust5 people · 12 points · first shared 2020 · discussion on HN
- 6Rust: Notes on Io-Uring5 people · 7 points · first shared 2020 · discussion on HN
- 7From Failure to Fehler5 people · 6 points · first shared 2020 · 1 comments on HN
- 8Async and Await in Rust: a full proposal4 people · 400 points · first shared 2018 · 190 comments on HN
- 9A final proposal for Rust await syntax4 people · 352 points · first shared 2019 · 261 comments on HN
- 10Async/Await I: Self-Referential Structs4 people · 2 points · first shared 2018 · discussion on HN
- 11Signing Git commits without gpg3 people · 3 points · first shared 2018 · discussion on HN
- 12Update on await syntax in Rust2 people · 275 points · first shared 2019 · 190 comments on HN
- 13Organizational Debt2 people · 185 points · first shared 2018 · 40 comments on HN
- 14Announcing failure: error handling for Rust2 people · 7 points · first shared 2017 · discussion on HN
- 15Ringbahn: A safe, ergonomic API for io-uring in Rust2 people · 4 points · first shared 2020 · discussion on HN
What HN people wrote when they linked it
carllerche · 2021-06-17
I believe it would be possible to implement using an edition in a way that any *old* code is compatible with new code.
Regarding implicitness, a lot in Rust already is implicit (e.g. type inference). Good implicitness only feels weird at first, before we get used to it. I linked to Aaron Turon's article on reasoning footprint, but as a follow up, there is withoutboat's article on "not explicit" that goes into the topic more: https://boats.gitlab.io/blog/post/2017-12-27-things-explicit-is-not/
newpavlov · 2021-03-10
>Our async IO model was based on the Linux industry standard (then and now) epoll, but that is not at all what drove the switch to a polling based model
Can you provide a link to a design document or at the very least to a discussion with motivation for this switch outside of the desire to be as compatible as possible with the "Linux industry standard"?
>the polling based model presents no issues whatsoever with io-uring
There are no issues with io-uring compatibility to such extent that you wrote about a whole blog post about those issues: https://boats.gitlab.io/blog/post/io-uring/
IIUC the best solutions right now are either to copy data around (bye-bye zero-cost) or to use another Pin-like awkward hack with executor-based buffer management, instead of using simple and familiar buffers which are part of a future state.
pornel · 2020-12-14
"Explicit" in language design is catch-all term for several different things: https://boats.gitlab.io/blog/post/2017-12-27-things-explicit-is-not/ (I highly recommend this article.) Defer is still manual and local, just less noisy and burdensome.
Just like every C feature: if you know how it's implemented (and optimized), you will know what is going to happen. All big C compilers already support stack frames and unwinding, so it's not even entirely novel functionality.
While you may object it's not entirely obvious how unwinding is going to be implemented, OTOH in functions with complex control flow it can be easier to understand which `defer`s are going to be run, as opposed to following nested `else` statements, or reasoning about the program state from all `goto cleanup` locations.
bschwindHN · 2020-04-09
I wouldn't recommend failure, its current maintainer and original author will be deprecating it:
https://boats.gitlab.io/blog/post/failure-to-fehler/
From the article:
> The crate I would recommend to anyone who likes failure’s API is anyhow, which basically provides the failure::Error type (a fancy trait object), but based on the std Error trait instead of on.
SeekingMeaning · 2020-02-07
For anyone interested in reading more about this, I would recommend Zero Cost Abstractions[1] by withoutboats, who is a contributor to Rust.
1: https://boats.gitlab.io/blog/post/zero-cost-abstractions/
coldtea · 2019-10-13
>Also, zero-cost abstraction is likely the biggest bullshit I've ever heard, there is a lot of cost and there's also a lot of waiting for compiler if you're using cargo packages.
"(...) there are two factors that make something a proper zero cost abstraction:
No global costs: A zero cost abstraction ought not to negatively impact the performance of programs that don’t use it. For example, it can’t require every program carry a heavy language runtime to benefit the only programs that use the feature.
Optimal performance: A zero cost abstractoin ought to compile to the best implementation of the solution that someone would have written with the lower level primitives. It can’t introduce additional costs that could be avoided without the abstraction."
https://boats.gitlab.io/blog/post/zero-cost-abstractions/
It's not about compile time...
weiming · 2019-08-19
A future is a one-shot generator, give or take.
Good reading list at the bottom of https://areweasyncyet.rs, starting with this post that uses generators as an example: https://boats.gitlab.io/blog/post/2018-01-25-async-i-self-referential-…
steveklabnik · 2018-02-07
Yes, the issue here is what happens on moves?
https://boats.gitlab.io/blog/post/2018-01-25-async-i-self-referential-… and the two follow up posts are the latest thinking on this topic, and by latest, I mean "posted in the last few days". This is cutting-edge stuff!
The intention is for this stuff to support Tokio; that is, generators make asyc/await work, which lets you write futures code more easily, to be run with Tokio.
nextaccountic · 2021-09-05
Rust generics can be written in a more compact way,
fn f(x: impl Test) { ... }
Is basically the same as
fn f<T: Test>(x: T) { ... }
Having to annotate the return value of functions is partly to make sure don't break semver accidentally, but it also constrains type inference to a local search rather than global search, avoiding spooky action at distance (when modifying a function changes the signature of another function). It seems that semver hazards are more important in languages with static types.
That pub? It's punching waaay above its weight! Having things private by default protects against semver hazards too, but it's also the major tool that enable writing safe code that uses unsafe { .. } blocks underneath. That's because a single unsafe block typically taints the whole module it's contained (such that even safe code needs a safety review). Being able to write safe abstractions of unsafe code is the pull of Rust so people need to get it right.
For example, setting the field len of a Vec to a value larger than what's initialized in its buffer will cause UB when accessing that memory; if this field weren't private, making a safe Vec would be impossible (likewise, a function that could set the len to any value must be private, etc).
So pub can only be used for things that are safe to export, and people should be careful with that.
Here's my least favorite syntax from there: that damn Ok(..). Ok-wrapping sucks. There were proposals to remove it, but they…
fluffything · 2020-04-09
The language team member you are criticizing for exploring what Ok-wrapping could look like goes into your particular argument in quite some detail here: https://boats.gitlab.io/blog/post/2017-12-27-things-explicit-is-not/
Your general concern, which is that "new syntax makes things less explicit, and is therefore bad", isn't logical.
Adding new syntax has many costs (not only one), but it can also have benefits (hence why it is being proposed), and the real question is whether the benefits outweigh the costs.
That is, whether it is a trade-off worth making.
In the blog post, the author quantify the actual costs of not having Ok-wrapping on their own code, as well as the costs of adding Ok-wrapping to the language, and for them, their numbers suggest that the trade-off is worth it - so they went on and implement it as a proc macro, and are using it on their own code. They don't care whether anybody elses uses it, and they don't have to.
You could have disagreed with their quantification, maybe you have different numbers, and that leads to a different outcome of whether the trade-off is worth making or not.
Instead, you just disagree, without making an argument, and others are doing the same.
In my eyes, this kind of hurts your position, since it gives me the impression that those against Ok-wrapping can't really argue why. Whether they just can't argue in general, lack data to back their arguments up, or maybe even whether they are Rust users at all, is anybody's…
Seattle3503 · 2025-08-22
> For example when submitting a write operation, the memory location of those bytes must not be deallocated or overwritten.
> The io-uring crate doesn’t help much with this. The API doesn’t allow the borrow checker to protect you at compile time, and I don’t see it doing any runtime checks either.
I've seen comments like this before[1], and I get the impression that building a a safe async Rust library around io_uring is actually quite difficult. Which is sort of a bummer.
IIRC Alice from the tokio team also suggested there hasn't been much interest in pushing through these difficulties more recently, as the current performance is "good enough".
[1] https://boats.gitlab.io/blog/post/io-uring/
pjmlp · 2023-05-08
Here is a kind of reference to the matter,
"What you don’t use, you don’t pay for. And further: What you do use, you couldn’t hand code any better."
https://boats.gitlab.io/blog/post/zero-cost-abstractions/
wging · 2022-01-31
One current gap is that async drops aren't currently a thing - you cannot do any async work to clean up a resource. I imagine Niko will point that out in the next post. See also https://boats.gitlab.io/blog/post/poll-drop/
stormbrew · 2021-03-10
I'm also curious about this. Boats wrote some about rust async and io-uring a while ago that's interesting[1], but also points out a very clear path forward that's not actually outside the framework of rust's Future or async implementation: using interfaces that treat the kernel as the owner of the buffers being read into/out of, and that seems in line with my expectations of what should work for this.
But I haven't touched IOCP in nearly 20 years and haven't gotten into io-uring yet, so maybe I'm missing something.
Really the biggest problem might be that switching out backends is currently very difficult in rust, even the 0.x to 1.x jump of tokio is painful. Switching from Async[Reader|Writer] to AsyncBuf[Reader|Writer] might be even harder.
[1] https://boats.gitlab.io/blog/post/io-uring/
gaogao · 2020-12-23
There's some interesting bits on the low-level work for using io_uring with the Ringbahn crate - https://boats.gitlab.io/blog/post/ringbahn/
nyanpasu64 · 2020-09-28
https://boats.gitlab.io/blog/post/notes-on-a-smaller-rust/ might be inspiration for such a language.
exrook · 2020-07-11
> That precludes GC
This isn't the case, there are tracing garbage collectors implemented as libraries [1][2], and there is consideration being made for supporting tracing GC in the language and stdlib [0]. As well as reference counted GC having been available in stdlib for a long time [3] (similar to C++'s std::shared_ptr)
[0] https://github.com/rust-lang/rfcs/blob/master/text/1398-kinds-of-alloc…
[1] https://manishearth.github.io/blog/2016/08/18/gc-support-in-rust-api-d…
[2] https://boats.gitlab.io/blog/post/shifgrethor-i/
[3] https://doc.rust-lang.org/std/rc/index.html
nickray · 2020-04-27
First, that's a limitation of git.
Second, it's easy to fake PGP: https://boats.gitlab.io/blog/post/signing-commits-without-gpg/
Third, we're adding support to SoloKeys to do this using a hardware token: https://github.com/solokeys/solo/issues/395#issuecomment-612059329
We're also collaborating with https://keys.pub/ to make "sign/verify" use cases easily usable with a GUI for everyone. So I'd say there's hope?
lightgreen · 2020-04-09
The final decision was made on 23rd of May, two weeks after new syntax was proposed and not even implemented yet. https://boats.gitlab.io/blog/post/await-decision/
ChrisSD · 2020-04-09
For those not familiar with the Rust drama, it should be emphasized that this blog post is very much a reaction to the linked blog post advocating for "Ok-wrapping": https://boats.gitlab.io/blog/post/why-ok-wrapping/
This is a subject that has provoked much drama in the past and looks like it will again.
beatgammit · 2019-10-01
If you still have issues with it, Cargo (Rust's package manager) has the option to use alternative package repositories, so you can host your own repository of packages[1] if you so choose. I haven't looked too far into it, so I don't know how painless it is to replace the default one or set up a mirror for packages you trust, but someone on Reddit claims to do just that at their company [2].
I wish Rust made it easier to know who the author of a package is (i.e. namespace packages so it's clear in the Cargo.toml), but I do think they've done a better job at designing crates.io than some other package repositories (i.e. npm).
[1] https://boats.gitlab.io/blog/post/2017-10-28-alternative-registries/
[2] https://www.reddit.com/r/rust/comments/9gl8p3/host_local_repo_than_cra…
Argorak · 2019-08-16
0-cost abstraction was summarised by Stroustrup as:
> What you don’t use, you don’t pay for. And further: What you do use, you couldn’t hand code any better.
In that mind-set, it is completely okay that `sync_read` and `async_read.await` can totally compile to something different, as they abstract different things.
Boats has some more thoughts on this here: https://boats.gitlab.io/blog/post/zero-cost-abstractions/
majewsky · 2019-07-18
I don't think you can reasonably have a Rust dialect without lifetimes. Ownership, borrowing and lifetimes is the very core of Rust. The other Rust submission on the frontpage right now explains this: https://boats.gitlab.io/blog/post/notes-on-a-smaller-rust/
est31 · 2019-06-12
async/await is right around the corner. Meaning few months give or take until it's on stable. The 1.37 goal [1] will most likely be missed though.
[1]: https://boats.gitlab.io/blog/post/await-decision-ii/
Macha · 2019-05-28
Why not JS/C#/Python style `await foo()` is discussed here:
https://paper.dropbox.com/doc/Await-Syntax-Write-Up-t9NlOSeI4RQ8AINsaS…
Main points against:
1. Interacts poorly with the ? operator for propagating errors. You'd need to do (await foo())?
2. Chains poorly. `await foo().bar().baz()`
- a. What are you awaiting? foo() or foo().bar().baz()
- b. What if you wanted to await foo().bar()? (await foo().bar()).baz() is messy.
- c. What if you wanted to chain promises? Like httpRequest.send().body() . In many libraries such as Python's requests, the first returns a future for a response with headers and only a later call waits until the body is returned. `await (await httpRequest.send()).body()`
Why not .await() or .await!():
https://boats.gitlab.io/blog/post/await-decision/
pas · 2019-01-17
https://boats.gitlab.io/blog/post/romio/ you can start playing with it right now
raphlinus · 2019-01-07
Thank you, Steve. You have personally done more to make the Rust community what it is today than possibly any other person. It speaks very poorly of Mozilla that they don't value your work.
Perhaps 2019 is the time to start the Rust Foundation, as mentioned by boats and others[0]. If so, you'd clearly be one of the founders. I would put my name into the ring for that as well, as we're now in somewhat similar circumstances. All it needs is some money, a lot for a pizza cook perhaps but a pittance by Silicon Valley standards.
Wherever our paths lead, I hope they continue to intersect!
[0]: https://boats.gitlab.io/blog/post/rust-2019/
dpc_pw · 2018-10-28
Sure we do: https://boats.gitlab.io/blog/post/shifgrethor-iii/ ;)
masklinn · 2018-06-18
There are known solutions to this problem: you can type-erase to a single supertype (e.g. Error/NSError[0]) or convert from the third-party's type to a first-party type[1] for instance.
[0] https://developer.apple.com/documentation/swift/error
[1] https://boats.gitlab.io/failure/
Lev1a · 2018-06-07
Let me introduce you to the concept of ErrorKind in Rust (i.e. in the IO module of the std): https://doc.rust-lang.org/std/io/enum.ErrorKind.html
There is also the "failure" crate which has patterns for the kind of thing you mentioned:
https://boats.gitlab.io/failure/error-errorkind.html
https://boats.gitlab.io/failure/custom-fail.html