Without boats, dreams dry up In Rust, there are certain API decisions about what is and isn’t sound that impact all Rust code.
That is, a decision was made to allow or not allow types which have certain safety requirements, and
now all users are committed to that decision. They can’t just use a different API with different
rules: all APIs must conform to these rules. These rules are determined through certain “marker” traits. If a safe API could do something to a
value of a type which some types don’t support, the API must be bound by that marker trait, so that
users can not pass values of those types which don’t support that behavior to that API. In contrast,
if Rust allows APIs to perform that behavior on any type, without any sort of marker trait bound,
then types which don’t support that behavior cannot exist. I’m going to give three examples to show what I mean, each of which Rust has considered at different
points, though only the first one actually exists in Rust. One of the most famous anecdotes that forms the basis of the United States’ political self-identity
is the story of an interaction between Benjamin Franklin and Elizabeth Willing Powel after the
Constitutional Convention of 1787, which established the United States’ present form of government.
Powel asked Franklin what sort of government the U.S. was to have, to which he replied: “a
republic, if you can keep it.” Given the self-conscious references to “constitutions” and “checks and balances” in the Rust
project’s recent governance RFC and the discourse around it, some further reflection on
this quote and its implications about governance as such might now be appropriate for the project
and its community. I have been devoting a lot of my free time in the past month to thinking about structured
concurrency, and a blog post about that is coming soon, but first I want to revisit iterators and
generators. In a previous post, I wrote about one of the hardest problems for generators:
self-referential generators. Unlike the Future trait when we were designing async functions, the
Iterator trait is already stable, and it does not take a pinned reference to itself. This means an
Iterator cannot be self-referential. This is the first post in a series of posts about concurrency in Rust, and the different APIs that
can exist to support it. Unlike my recent series on control-flow effects, this series isn’t driving
toward any particular vision of what I think the Rust project should do. Instead, I am just trying
to publicly explore the problem space and build tools for thinking about the issues involved. I’m
not sure what the “right” concurrency API is. One of the main emphases of my recent posts has been that I believe shipping generators would solve
a lot of user problems by making it easy to write imperative iterative code, and especially to make
that iterative code interact well with asynchrony and fallibility as well. One thing that frustrates
me about the situation is that generators have been nearly ready to ship for years now, but very
little visible progress has been made. In particular, the core compiler transform to take a
generator and produce a state machine already exists, because it’s exactly how async functions are
implemented. In a previous post, I established the notion of “registers” - code in Rust can be
written in different registers, and it’s important to adequately support all registers. I
specifically discussed the low-level interface of the AsyncIterator trait, about which there is
currently a debate. The interface it currently has is a method called The previous two posts in this series tried to discuss the design of Rust through the lens of some
higher level language concepts: This post does not introduce any such high-minded concept. It is entirely down in the weeds. That’s
partly because it is based on content I removed from the previous post so that post could focus on
the higher point. This is the second post in an informal series commenting on the design of async Rust in 2023. In my
previous post, after a discussion of the “registers” in which control-flow effects could
be handled in Rust, I promised to turn my attention to recent proposals around a concept called
“keyword generics.” For reference, there are two posts by the current design team of Rust that are
my reference point for this commentary: I’m not going to reiterate these blog posts at length, but in brief “keyword generics” is a proposal
to introduce a new kind of abstraction to Rust, to allow types to be abstracted over certain
effects. The examples have focused on It’s been nearly two and half years since I was an active contributor to the Rust project. There are
some releases that I’ve been very excited about since then, and I’m heartened by Niko’s recent blog
post emphasizing stability and polish over grand new projects. But I’ve also felt a certain
apprehension at a lot of the directions the project has taken, which has often occupied my thoughts.
From that preoccupation this blog post has emerged, hopefully the first in a series over the next
few weeks outlining my thoughts on the design of Rust in 2023, especially in connection to async,
and I hope its impact will be chiefly positive. In the previous post in this series, I wrote about how the core state machine of
ringbahn is implemented. In this post I want to talk about another central concept in
ringbahn: “drivers”, external libraries which determine how ringbahn schedules IO operations
over an io-uring instance.Changing the rules of Rust
A governance system, if you can keep it
Iterator, Generator
The Scoped Task trilemma
Generators
The AsyncIterator interface
poll_next
, which is a “poll”
method like Future::poll
. Poll methods are very “low-level” and are harder to write correctly than
async functions. Some people would like to see AsyncIterator
shifted to have an async next method,
simply the “asyncified” Iterator
trait.Const as an auto trait
Patterns & Abstractions
async
and const
as the effects, but there is sometimes
discussion of try
as well. Astute readers will notice this is an overlapping but not identical set
of effects to the effects I identified in my last post; I did not mention const
as an effect, and
as far as I know the keyword generics working group has not devoted much or any time to considering
iteration as an effect.The registers of Rust
Ringbahn III: A deeper dive into drivers