• Anonymous Impls

    I often find myself writing a function that internally defines a struct just so I can implement a trait on it and return that type as an impl Trait. To see what I mean, let's look at a concrete example. We'll write a function that takes an iterator that yields, for example, 1, 2, 3, 4 and returns a new iterator that yields (1, 2), (3, 4).

    /// Assumes the input iterator yields an even number of elements.
    fn adjacent_pairs<I: Iterator>(xs: I) -> impl Iterator<Item = I::Item> {
        struct Pairs<I: Iterator> {
            xs: I,
        }
        
        impl<I: Iterator> Iterator for Pairs<I> {
            type Item = I::Item;
            
            fn next(&mut self) -> Option<Self::Item> {
                let first = self.xs.next()?;
                let second = self.xs.next()
                    .expect("source iterator must have even length");
                
                Some((first, second))
            }
            
            fn size_hint(&self) -> (usize, Option<usize>) {
                let (size, max) = self.xs.size_hint();
                
                (size / 2, max.map(|max| max / 2))
            }
        }
        
        Pairs {
            xs,
        }
    }
    

    There's a mildly annoying amount of ceremony here. We have to define a struct that we construct exactly once. We also have to duplicate the type parameters basically everywhere. It's not the end of the world, but what if we could make this a little shorter?

    This is where a potential new Rust feature called anonymous impls could help.

    Read more...
  • Two Ways Not to Move

    Lately I've been talking to a few people about whether it might be possible to replace the Pin wrapper in Rust with a new Move trait. Pin is one of those things that, while amazing that Rust can express the concept and semantics using just a library type, is not a lot of fun to use. This creates friction in building out Rust's async features because currently doing so increases the opportunities for users to be exposed to Pin. Maybe we can just get rid of Pin entirely?

    One possible way to do this is with a trait called Move. This would be a trait that most types implement and indicates that you have the ability to perform a move operation on a value of that type. It's sort of like the Send trait, where when a type implements Send it means values of those types can be sent to another thread.

    This trait was considered somewhere in the Rust 2015 and 2018 timeframe but was rejected in favor of Pin instead. The main reason is that Pin could be added in a way that meets Rust's stability guarantees. Indeed, how to add Move now is a huge problem that we're going to entirely ignore in this post.

    I recently discovered that the version of Move that was originally considered worked quite different from how I would have expected. As a result, we accidentally have two Move designs. In this post, I want to briefly describe each one and then discuss some of the tradeoffs they make.

    Read more...
  • Some Rough Thoughts on Rust Project Organization

    One of the big priorities for the Rust Leadership Council has been to determine the "shape of Rust." For a long time I've wanted to write a comprehensive blog post about what I think the shape of Rust should look like. Unfortunately, I've had too many competing priorities to write something fully comprehensive. This post is not that post, but I did want to try to put down a couple ideas I've been thinking about recently.

    I want to touch on three things. These aren't necessarily in priority order or anything, but they are all things that I think would be useful for various reasons. The three things in this post are:

    1. Create structures for support roles
    2. Create a Design Team
    3. Separate Project Membership from Team Membership
    Read more...
  • A Rose By Any Other Name

    There are currently two competing designs for async iteration traits for Rust. The first is poll_next. The second is async fn next. I see strengths to each design. The poll_next design seems stronger on technical concerns, such as performance and ease of implementation. The async fn next design seems better from an ergonomics and consistency perspective. Unfortunately, the process of resolve this debate has been slow going.

    One thing I've realized in the debate is that at this point the two designs are more similar than they may seem at first glance. In this post I'd like to show how a handful of minor tweaks to each design results in something that is the same modulo names.

    Read more...
  • Async Cancellation and Panic

    When I last wrote about async cancellation in Rust, I touched briefly on the question of how cancellation interacts with panic. Mostly I left it as an exercise for the reader and left a rough sketch for how I thought it would work. More recently, Boats touched on the issue in a little more detail, but I think there are still a lot of open questions. In this post, I'd like to experiment with unwinding using my cancellation prototype and build on some of the previous work in this area.

    Read more...
  • How to Shrink Rust

    While doing some housekeeping on my blog over the weekend, I can across an ancient post by Patrick Walton. While I didn't realize it at the time, this post embodies what has become one of my core principles in program language design.[^spiky-blob] In re-reading Patrick's post, this quote stood out in particular:

    Language design tends to go in cycles: we grow the language to accommodate new functionality, then shrink the language as we discover ways in which the features can be orthogonally integrated into the rest of the system. Classes seem to me to be on the upward trajectory of complexity; now it’s time to shrink them down. At the same time, we shouldn’t sacrifice the functionality that they enable.

    This cycle of growing and shrinking as a key part of the process in the early days of Rust. Upon reading this section, I found myself asking "how could we shrink Rust today?"

    Read more...
  • Rethinking Rust's Function Declaration Syntax

    We had a fun discussion in #t-lang about possible new syntax for declaring functions in Rust. There were a lot of cool ideas put forward, and while mulling them over I realized a lot of them work nicely together and can be introduced in a backwards-compatible way to give us some cool new capabilities. While these were fresh in my mind and I'm feeling excited about them, I wanted to write them in one place.

    Read more...
  • A Mechanism for Async Cancellation

    One of the items on our Async 2027 Roadmap is to come up with some kind of asynchronous cleanup mechanism, like async Drop. There are some tricky design questions to making this work well, and we need to start thinking about these now if we want to have something ready by 2027.

    In this post, I'd like to explore a low level mechanism for how we might implement async cancellation. The goal is to explore both how an async executor1 would interact with cancellation, as well as to make sure that this mechanism would support reasonable surface-level semantics. You can think of this as a kind of compilation target for higher level features, similar to how the Rust compiler lowers async fn into coroutines.

    Read more...
  • Cancellation and Async State Machines

    If you've been doing async for a while, you've probably heard someone say something like "the compiler takes an async function and converts it to a state machine." I want to dive into this more, since we can think of cancellation as making the state machine more complex. In this post, I'll show how to build a state machine for a simple async function. Then we'll we'll see how the state machine changes if we want to be able to run async code during cancellation. Finally, we'll explore some of the design space around cancellation, particularly what happens if a future that has been cancelled is cancelled again, and see how state machines can suggest several possibilities.

    Read more...
  • Ideas on How to Elect Rust Project Directors

    One of the first tasks for the Rust Leadership Council is to elect new Project Directors. But before we can do that, we need to create a process for doing so. To do this, and in the spirit of delegation from the Leadership Council, we've formed a smaller group to focus on designing this process. This group so far consists of myself, Jane Losare-Lusby, and Ryan Levick.

    We have the beginnings of a proposal, but I wanted to write it up in my own blog to help make sure I understand it. Note that this is a draft proposal at best at this point and nothing is set in stone. I also want to recognize Jane's work in coming up with this process. This is largely based on her initial suggestion and I want to make sure I'm not taking credit for something I didn't come up with. But, any failings in this post should be viewed as my own and not hers.

    Read more...
See all posts