There is good news, though! Rust is a powerful language when it comes to encouraging robust code through warnings and compile-time errors, and we can take advantage of that. Here's how... 10/29
-
Show this thread
-
Let's replace JoinHandle<T> with a new type simply called Task<T> that is very similar except it also acts like a guard that cancels the task when dropped. Task<T> is an awaitable future that resolves to a value of type T, which is the task's result. 11/29
2 replies 0 retweets 6 likesShow this thread -
When a task is cancelled, it gets immediately woken and the next time the executor takes it out from the task queue, it will be simply dropped. Automatic cancellation is one of the core tenets of structured concurrency. 12/29
1 reply 0 retweets 3 likesShow this thread -
Task<T> is also marked with #[must_use], so if you accidentally drop it without ever using it, the compiler warns you. That aligns closely with how futures typically work - dropping a future implies its cancellation. 13/29pic.twitter.com/dqAI9mWFUY
1 reply 0 retweets 6 likesShow this thread -
If you want to keep the task running in the background with no strings attached, forget() its Task<T> handle. 14/29pic.twitter.com/USMwYCt1pL
2 replies 0 retweets 2 likesShow this thread -
But here's the catch: you can only forget() tasks that resolve to (), which means you can't accidentally forget() a task that resolves to a Result or some other type. Now spawn(process(stream)) doesn't even compile - problem solved! 15/29
2 replies 0 retweets 9 likesShow this thread -
The compiler now requires us to unwrap results in spawned tasks. But it'd be nice to have some API sugar here that is not as verbose as this... 16/29pic.twitter.com/YB7eLhDSgh
1 reply 0 retweets 2 likesShow this thread -
What if there were unwrap() and expect() methods on Task<Result<T,E>> that transform it into Task<T> and panic on error? Those methods spawn a new task that simply unwraps the result and returns the success value. 17/29pic.twitter.com/7eQfRDqSN8
1 reply 0 retweets 2 likesShow this thread -
Now we can do spawn(process(stream)).unwrap().forget(), which is pretty nice! This is what the entire TCP echo server looks like in my new runtime I'm working on. 18/29pic.twitter.com/H9Z2Nm9TOJ
3 replies 0 retweets 11 likesShow this thread -
Finally, what about panics? Tokio silently ignores panics, meaning they might accidentally slip through. In particular, if an assertion fails in a task spawned from tokio within a unit test, the test will pass when it should fail! 19/29pic.twitter.com/3Mf9WskU4I
2 replies 0 retweets 5 likesShow this thread
Correction: awaiting a JoinHandle gives a Result indicating whether the task panicked so we get a compile-time warning. Tokio handles this case well. This was not a good example. A case where tokio loses errors without warning is: let _ = task::spawn(future_outputting_result);
Loading seems to be taking a while.
Twitter may be over capacity or experiencing a momentary hiccup. Try again or visit Twitter Status for more information.