-
Lightweight, Predictable Async Send Bounds
The last week or two has been exciting in Rust async land. We're making great progress on one of the open questions around async functions in traits, and I think we're close to being ready to propose something officially. In this post, I'd like to describe the proposal and discuss some of the tradeoffs and open questions with it.
We've had a couple of ideas going around so far. One of the main ones is Return Type Notation (RTN), which Niko describes in his recent post. In my last post, I suggested that we could infer the necessary bounds in many cases.
While I was excited about inferring bounds at first, one major shortcoming is that it creates new semantic versioning hazards. The inference depends on the body of the the function you've annotated, which means when modifying the function you could easily add or remove bounds from the signature by accident.
In the discussions we've had since then, we have been converging on a solution that we expect will work in the common cases, but avoids both the verbosity inherent in RTN and the semver hazards with inferring bounds. This is the solution I'll be describing in this post.
Read more... -
Inferred Async Send Bounds
One of the issues we're working on with async functions in traits for Rust is how to attach
Send
bounds to futures returned by async methods. Niko Matsakis has been writing on this subject recently, so if you haven't seen his posts, definitely check them out! His first post outlines the problem, while the second post introduces a possible solution: Return Type Notation (RTN). I'm going to write this post assuming you're familiar with those.I'm mostly a fan of the proposed return type notation. It's a very powerful feature that gives a solution to the
Send
bound problem but is also generally useful in other cases. There are some significant shortcomings though, so I don't think it should be the only or even primary solution people reach for to solve theSend
bound question.In this post I'd like to explore some more implicit approaches that address the issue while using much lighter syntax.
Read more... -
Hello from Eric's Blog Generator
As of my previous post, I'm now generating this site using my very own static site generator that I've creatively named Eric's Blog Generator or EBG for short. Depending on how you count, this is the about the fifth time I've changed blogging platforms.
Some History🔗
It's not totally clear what counts as "this blog" but in my mind the first version of it started when I was an intern at Mozilla back in 2011. Mozilla encouraged us to blog and my manager recommended Tumblr, which was the style at the time. So I made four whole posts about my contributions to a new systems programming language called Rust that was designed to be safe, practical, and fast. This language was going to change the world with cool features like typestate! I worked on Rust's concurrency and parallelism features, and if I remember right, my main contribution that summer was Rust's first green threading system.
Then in March of 2012 I started blogging at WordPress. The first few posts were about things I was working on in grad school, but that summer I went back to work on Rust at Mozilla so I wrote quite a few posts about Rust. I was pretty proud of the protocols feature that I added, which let you define communication protocols that pairs of tasks could follow and the compiler would make sure you sent and received the right messages at the right time. On aspect I was particularly proud of was that in some cases the compiler could prove there was an upper bound on the number of messages that could be in flight, so it could pre-allocate the necessary space and message passing would be zero allocation. Anyway, like most intern projects, this one was ripped out pretty much immediately after I left. It turns out people only ever used two protocols—one-shot and stream—so Rust just included these two in the library and got rid of the complexity of letting people define arbitrary communication protocols. Given that Rust has proc macros now, I've often thought it would be fun to reimplement protocols as a macro. I did make one contribution that stuck around and has enabled many of the concurrency bugs that occur in real-world Rust programs.
That November, after going back to school I migrated to Octopress, which was the style at the time. This was also when I moved to my own domain, where the site lives to this day. I still have fond memories of Octopress. It seemed effortless to create, write, and publish new blog posts. I think of this era as kind of my golden age of blogging.
I used Octopress 2.whatever for a while, but in 2017 it was time to migrate to Octopress 3.0. I'm honestly not sure why I did this. The old way worked fine and I never really got comfortable with the new way. Octopress 3.0 was purely a Jekyll plugin, while 2.0 was more of a wrapper around Jekyll. In theory this should have been simpler, and it should have opened up the wider Jekyll ecosystem. Instead, I basically forgot how to work my blog. Something needed to change.
Why did I write my own?🔗
First, as I mentioned, I was never really happy with my blog after upgrading to Octopress 3.0, so I was on the lookout for something different. One challenge for me was that Octopress and Jekyll were Ruby-based, and I've never really gotten comfortable working with the Ruby ecosystem. Every time I wanted to write a new post I had to remember how to deal with bundler and Gemfiles and whatever else you have to worry about with Ruby. Furthermore, I tend to work from a number of different computers, and the Ruby environments never worked quite the same in each spot. I tried dockerizing my blog but I'm also not really good with Docker. Finally, I designated one computer as the one where blogging works and I'd SSH into it any time I wanted to work on my blog. The whole setup was suboptimal.
These days I work mostly in Rust and I love working with cargo and the rest of the Rust ecosystem. Rather than learn some other language ecosystem, I wanted to be able to be able to stick with one I know well and use regularly. There are already static site generators written in Rust, and I looked at some of these, but I wasn't convinced these would give me everything I was wanting. I wanted something that I could do a mostly in-place upgrade. Even moving from Octopress 2.0 to 3.0 required some pretty gnarly git-fu since I basically had to transplant from Octopress 2.0 where everyone just forked the original Octopress repo to Jekyll where the tooling creates a new standalone site for you. I wanted to be able to leave my existing posts basically in tact, although I was willing to make minor edits if it was easier to edit them to not need a feature rather than support a feature in my own generator. Also, I wanted something that I could install by doing
cargo install
and expect it to work, but some of them required additional build steps that I didn't want to deal with.Finally, writing code is fun and this has been a fun little project to work on. And given that I'm trying to make Rust a better language, it makes sense to spend some time using Rust to stay rooted in how the language feels as a user.
As a bonus of having written my own, I'm now in a good position to try out some ideas I've wanted in a blogging platform for a while. Sure, Jekyll and similar platforms have lots of plugins and I could probably find or write plugins that work, but writing my own software saved me from having to learn someone else's. (Isn't there some saying like one month of coding can save you one hour of reading documentation?) For example, I'd like to try out different ways of rendering footnotes, add captions for images, and so on. One thing I'd like to try is automatically adding <archive.org> links for any external pages I like to, since I've noticed after blogging for twelve years that sometimes things I link to don't stay up. My new blog generator doesn't do any of these things yet, but now I'm in a good place to add these features if I'm so motivated.
Can I Use Eric's Blog Generator?🔗
You can if you want to, but honestly, there are many better options out there. While it's good enough that it now powers this site, it's missing some rather basic features. For example, you have to write your own theme from scratch. That said, the code is out there, it's published on crates.io, and there's even a Docker image.
And since people like feature lists, here are some reasons why you might want to use Eric's Blog Generator:
- Easy installation, just
cargo install ebg
. - Somewhat Octopress compatible. Your source posts should work with minimal edits, although EBG doesn't support SCSS or Liquid templates so you'll have to redo your theming.
- Cross platform. I use it on Windows and Linux and I can't think of why it wouldn't work on Mac or any other platform that Rust supports too.
- Supports writing posts in Markdown.
- Supports static pages in addition to blog posts.
- Flexible templates powered by Tera.
- Used by some of the greatest writers in the world!
Conclusion🔗
Well, I thought this was going to be a short post just to say "I made a blog generator and it's now powering this site!" Instead I got a little nostalgic and took a tour through all the earlier incarnations of this blog and this turned out to be kind of long. With any luck, this should be the last version I ever need, because now I can just change things if my tools aren't working for me anymore. I'm hopeful that this will remove some of the friction I've had with writing and publishing in the past so I'll be able to post a lot more regularly. Of course, the bottleneck is always the actual writing, not the tooling...
- Easy installation, just
-
Who Makes the Boxes?
As I've written about before, one of the major features we're working on adding to Rust is to allow async functions in traits. Today we have support in nightly for async methods in traits in static contexts. This lets you write code like the following:
trait AsyncCounter { async fn get_value(&self) -> usize; async fn increment_by(&mut self, amount: usize); } async fn use_counter(mut counter: impl AsyncCounter) -> usize { counter.increment_by(42).await; counter.get_value().await; }
This empowers a lot of use cases, but we also want to support this feature in dynamic dispatch contexts. In other words, we'd like to be able to write
use_counter
like this:async fn use_counter(mut counter: &mut dyn AsyncCounter) -> usize { counter.increment_by(42).await; counter.get_value().await; }
While this looks like a straightforward extension on what we already have, I've been surprised by the amount of additional functionality needed to support this change.
It turns out there are also a lot of design questions that in my mind do not have an obviously right answer. There are cases to be made for many different points in the design space, but ultimately the right one will depend on what people use in practice.
In this post, I'd like to explore the space for one of these questions.
Read more... -
Async Functions in Trait Objects Update
As 2022 draws to a close, I want to take a moment to look at where we are with supporting async functions in dyn traits (AFIDT) and suggest some ideas for how to make progress in 2023.
The set the stage, we'd like to make the following snippet of code work:
trait AsyncCounter { async fn increment_by(&mut self, amount: usize); async fn get_value(&self) -> usize; } async fn use_counter(counter: &mut dyn AsyncCounter) { counter.increment_by(42).await; counter.get_value().await }
Through the rest of this post we'll see how close we are to getting that working and what's left to get it across the finish line.
Read more... -
A Look at dyn* Code Generation
As I've written about before, an important goal for async Rust is to support async functions everywhere, including in trait objects (
dyn Trait
). To this end, we are adding a new experimental type calleddyn*
that will give us more flexibility to support dynamic dispatch for async methods. We now have experimental support fordyn*
in nightly Rust now, so we can start to kick the tires and use our experience to inform future development.One thing we'd like to ensure is that using
Read more...dyn*
does not impose significant costs above what's already incurred bydyn
. Ideally we'd be able to generate essentially the same code fordyn* Trait
that we do fordyn Trait
. With that in mind, in this post, I'd like to look at some of the code we currently generate. We'll start by looking atdyn Trait
objects, and then we'll see how things change fordyn* Trait
. -
Something That Confused Me About Rust Specialization
I recently read through RFC 1210 to understand Rust's proposed specialization features. I found the example given in Going down the rabbit hole confusing, so I started writing a question to post to IRLO. In the course of writing up my question I also figured out the solution, so now I'm posting my solution here instead.
Read more... -
More Weekly Links
Continuing the series I started a few weeks ago, here are links to things I've found interesting recently.
Read more... -
Links For This Week
Sort of in the same vein as my last paper review post, I'd like to start periodically posting a weekly links post. In theory I should publish this every week, but I don't want to make a hard time commitment. Instead, I'm going to make a point of writing up little blurbs about things I find interesting and publishing that when I have enough. These can be things I'm reading, things I'm watching, or anything else, but the key thing is that I found them interesting in some way and perhaps they led to some change in how I'm thinking about or doing things.
Read more... -
Paper Review: Safe, Flexible Aliasing with Deferred Borrows
I'm trying something new today. I try to periodically read papers and such to stay on top of the latest research on things I'm interested in. Unfortunately, it's easy to read a paper and have it not really stick. To combat that, today I'm trying a paper review. We did this in some of my classes in grad school, where we'd have an assigned reading for each class period and before that we were supposed to write a couple paragraphs summarizing the paper, evaluating it, and asking a few questions. So, in what will hopefully become a regular feature of my blog, today I'm kicking off my first paper review.
Today I'm reviewing Safe, Flexible Aliasing with Deferred Borrows by Chris Fallin. This was published in ECOOP 2020. I found out about this paper from Yosh Wuyts who mentioned that it might be a good theoretical foundation for adding
Read more...defer
expressions to Rust.