6 ms·
At the risk of sounding like a broken record, Rust attacks this problem from multiple avenues... 1. You can tag a type or function as #[must_use], either of wh
by Nullabillity 6y ago
At the risk of sounding like a broken record, Rust attacks this problem from multiple avenues...
1. You can tag a type or function as #[must_use], either of which makes discarding a value trigger a warning. This would have caught the (equivalent of the) example code.
2. Futures provide pretty much everything that Context does, but without having to thread a magical value correctly through everything. Explicit cancellation can be had just by.. dropping the Future. This means that you can get timeouts by racing with a timer Future. Arbitrary values (as in the example) are slightly more verbose, but you can have a decorator Future that sets a thread-local for the duration of the poll.
- Thaxll 6y agoIf don't find decorator / tags in programming elegant, it polutes your code so much.
- oh_sigh 6y agoHow would you like to tag functions or things with properties (like the "return value must be used" property?
- bigdubs 6y agoGodoc. This less applies to something needing to be "used" as much as something needing to have an action taken in a `defer` like `.Close()` etc.
- BoorishBears 6y agoWhat's wrong with formalizing a way to have tooling give that information at the call site? There's no reason the directive couldn't be compatible with Godoc either? The only argument I can see is that it's a "slippery slope", but that's a pretty tired argument, you can use it against most any sort of progress in a language.
- bigdubs 6y agoWhat would the goal be; for the compiler to warn if a type requires a method to be called on defer? What if you want to let the caller of the caller handle that? You would then need pragmas to silence the warning, which is something that the authors specifically don't want.
- Nullabillity 6y agoThe Rust answer would be that you implement `Drop` for your type, rather than asking you nicely to remember to close everything properly.
- bigdubs 6y agoCloser is an interface in go that you can test for, the issue here is interfaces are implicit in go.
- morelisp 6y ago> for the compiler to warn if a type requires a method to be called on defer? This seems a bigger ask than what's upthread and than what's necessary in most cases. You just need to make sure the return value is not implicitly discarded. Go linters already do this for `error`. I have used both __checkReturn and __attribute__ ((warn_unused_result)) in C projects before and both were helpful, easy to reason about when the warning occurred, easy to work-around in the rare cases I really truly did want to drop the result (in Go `_ = ...` is already idiomatic), and useful in semantically varied cases (resource allocation, error handling, pure functions).
- oh_sigh 6y agoIsn't this essentially annotations hidden in a comment?
- networkimprov 6y agoRust also permits termination of blocking syscalls. Once upon a time it automatically retried many syscalls after EINTR, but it dropped that design flaw.
- papaf 6y agoExplicit cancellation can be had just by.. dropping the Future. Its great to have a Rust expert to turn up in a Go thread to educate the masses. I have one question from the cheap seats though. How do you drop the Future, with a decision made at runtime, given that lifetimes are part of the type system? Thanks for your help.
- Nullabillity 6y agoIt's not very useful to borrow futures, so that tends not to be an issue in practice.
- msbarnett 6y ago> I have one question from the cheap seats though. How do you drop the Future, with a decision made at runtime, given that lifetimes are part of the type system? Trivially, something like let future = some_long_running_async_function(); let timer = delay(Duration::from_millis(10000)); select! { result = future => { // handle result of future completing successfully }, _ = timer => { // future missed the deadline, drop it, terminating execution. std::mem::drop(future); } } If this were wrapped in a function you could also just return out of the timer branch and let the future naturally drop as the stack popped.
- clktmr 6y ago> Futures provide pretty much everything that Context does, but without having to thread a magical value correctly through everything. It has downsides though: * Instead you have to use async/await throughout your code and suddenly have two execution models that you need to reason about * Dropping the future won't help if the call is hanging on a blocking call either * The callee doesn't know anything about a possible deadline * You can only handle the cancellation in the callee in `Drop`, which gets complicated quickly if you need to rollback changes, because you need to track state manually * After all the use of 'context' is optional. You only need to pass it if you need cancellation, whereas in async Rust you always need to keep in mind that you might get canceled.