Earlier quoted context omitted.
In a systems context, where performance and memory ostensibly matter, why wouldn’t you want to be made aware of those inefficiencies? Sure, Go hides all that, but as a result it’s also possible to have memory leaks and spend extra time/memory on dynamic dispatch without being (fully) aware of it.
I think Rust is also able to hide certain things. Without async things are fine: type Handler = fn(Request ) -> Result , Error>; let mut map: HashMap = HashMap::new(); map.insert("/", |req| { Ok(Response::new("hello".into())) }); map.insert("/about", |req| { Ok(Response::new("about".into())) }); Sure, using function pointer `fn` instead of one of the Fn traits is a bit of a cheating, but realistically you wouldn't wa…
I don't think this a reasonable in Rust (or in C/C++). I 90% of the pain of futures in Rust is most users don't want to care about memory allocation and want Rust to work like JS/Scala/C#.
When using a container containing a function, you only have to think allocating memory for the function pointer, which is almost always statically allocated. However for an async function, there's not only the function, but the future as well. As a user the language now poses a problem to you, where does the memory for the future live.
1. You could statically allocate the future (ex. type Handler = fn(Request) -> ResponseFuture, where ResponseFuture is a struct that implemented Future).
But this isn't very flexible and you'd have to hand roll your own Future type. It's not as ergonomic as async fn, but I've done it before in environments where I needed to avoid allocating memory.
2. You decide to box everything (what you posted).
If Rust were to hide everything from you, then the language could only offer you (2), but then the C++ users would complain that the futures framework isn't "zero-cost". However most people don't care about "zero-cost", and come from languages where the solution is the runtime just boxes everything for you.