I'm in favor of an attribute like this. Using a blocking function inside an
async context is a very inconspicuous error. Blocking functions are very common both in the standard library and in the whole ecosystem. Using them in an
async context compiles without warnings, it passes all your tests, it even runs fine in production as long as you don't actually stress the system. You could write an http server with blocking code in its
async functions that runs fine for months until one day you get a traffic spike and only then performance falls off a cliff.
And even then, you might have a very hard time finding that the root cause of your poor performance is that you used some blocking functions somewhere in your entire application. It might not even be you who does the blocking, it could happen in some unexpected place in a library somewhere. And even if you suspect blocking calls to be the issue, finding these blocking calls doesn't sound easy either.
It is really the worst kind of error: easy to make, hard to detect (both in the code and at runtime), and hard to debug, so an attribute like
#[might_block] would be very useful. It makes the error harder to make and easier to detect. This attribute will never be able to catch all mistakes without changes to the type system (e.g.
Option::map should be
#[might_block] if and only if its argument is
#[might_block]), but it's good enough even if we just catch some of the mistakes, both as a teaching tool for new users who might not be aware of this issue, and as an extra line of defense against slip ups by experienced users.
I agree that
#[might_block] should theoretically be transitive, in the sense that using a
#[might_block] function inside another function (not marked
#[might_block]) should give a warning that you should also mark that function
#[might_block]. But from a practical point of view, I'm not so sure, because that would create lots and lots of warnings, nagging people to mark functions as
#[might_block] even though they were never intended to be used in an
async context. Perhaps this transitive warning should only be applied to
pub functions in libraries. (EDIT: maybe this transitive warning should just be a clippy lint?)
I'm also not sure how pedantically
#[might_block] should be applied to functions that can technically block but rarely do. As mentioned in this blog post, even
println!() can technically block, but the times where that will actually cause an issue seem to be extremely rare. I think adding
println!() would not be a good idea.