So let me be very clear: if you as a maintainer feel that you control who or what can use your code, YOU ARE WRONG.

  • sugar_in_your_tea
    link
    fedilink
    arrow-up
    2
    ·
    8 hours ago

    Rust lacks them, but so far that seems to me to be a shortcoming in Rust

    I think it’s a benefit. In Rust, you have two options:

    • panic - usually catchable with catch_unwind() (some types are not), and should be used rarely, this isn’t try/catch
    • result - return a value that indicates an error, like a super fancy errno, but with monad semantics that force you to acknowledge it

    This is good for a few reasons:

    • “normal” errors are explicit in the return type; if a function doesn’t return a result, it can’t return errors
    • outliers aren’t accidentally handled - since you shouldn’t be catching panics, you can rely on them to completely crash
    • no need to instrument the code with unwinding logic in case something throws an exception, meaning a more efficient runtime

    Where do the call stacks for the different async tasks live and how are they allocated?

    The async runtime handles that. You’d need to look at the specific implementation to see how they handle it, the standard library only provides tools for dealing with async.

    My understanding is that it works kind of like a generator, so any await call yields to the runtime, which resumes another generator. That’s an over simplification, but hopefully it’s close enough.

    Call/cc

    I think this is basically just the general idea of a generator, but the caller chooses where the yield yields to.

    I agree with the criticisms of call/cc, and I think it’s much clearer to just use coroutines (of which generators are a special case) and otherwise linear control flow instead of messing about with continuations. IMO, the only people that should mess with continuations are lower level engineers, like driver authors, compiler devs, and async lib devs. Regular devs will just create more problems for themselves.