It’s annoying magic like that that bothers me.
Another example is async lifetimes - it’s frequently hard to properly express the lifetime of a borrow resulting in choices of an unnecessary Box::pin, unsafe or even both. Here’s an example i ran into recently and the author’s challenges there are similar to the one’s I’ve ran into in my own codebase [1]
Or how about bridging poll-based futures and async (eg if within my poll interface I want to call an async method). It’s weird how there’s a world of difference between the implicit future generated by async and an explicit type implementing Future. I understand the similarity to named function vs closure but I’m finding the distinction to have far more annoying sharp edges than I’ve experienced with closures.
The tooling around non-trivial programs is also unfortunate - working with an io_uring async runtime and Miri fails to start (noted limitation). Valgrind deadlocks for some reason as well which means that only asan’s more limited techniques are usable.
My point is that soundness issues writing unsafe code is important but a niche topic vs what I’ve experienced writing a substantial program in Rust (~40k lines of code so far). It’s doable but I find myself still fighting with the language just a bit too much.
Hopefully it’s completely different teams responsible for these kinds of work but, if not, I’d vote for stabilizing some of the ergonomic magic that std has access to and improving the borrow checker to recognize more definitely safe constructs so that users don’t need to do annoying hoop jumping. I know the std magic I referenced is being worked on but as with all things rust it’s impossible to predict what actually gets stabilized and when with the exception of marquee tentpole features they talk about on the blog.
[1] https://github.com/someguynamedjosh/ouroboros/issues/112