4 ms·
you don't want exception-style "convenience", that's the whole point you want to be able to read code and see a single control flow ? subverts that core requi
by preseinger 3y ago
you don't want exception-style "convenience", that's the whole point
you want to be able to read code and see a single control flow
? subverts that core requirement
- nulld3v 3y agoThe problem with exceptions is that they can come from any line of code and cause a "return". Rust's question mark solves the issue because it marks which lines of code can cause a "return". Therefore, you can always see see the control flow of a function. Moreover, you can go even further if you really really really want a single control flow. You can write a clippy lint to disallow early returns (ban "return" keyword) and question marks. That said, I really don't think this is a good idea. The "return" keyword exists for a good reason.
- preseinger 3y ago? enables chaining, chaining subverts comprehensibility in exactly the ways i'm describing
- consilient 3y agoAll languages have chaining: that's what `;` is for. Chaining together transitions in an imperative state machine isn't simpler than chaining together `Result`s, you're just used to it.
- preseinger 3y agochaining means combining a sequence of expressions that each take the same input as they give as output ; doesn't do this, afaict when you're writing imperative code it's important that control flow (return) is explicitly visible
- consilient 3y ago> chaining means combining a sequence of expressions that each take the same input as they give as output > ; doesn't do this, afaict It's chaining together transitions in the state machine that is your program. > when you're writing imperative code it's important that control flow (return) is explicitly visible Control flow is visible with `?` or other do-notation variants. If I want to error out in a `Result` context, I explicitly return `Err(bad stuff)`. And if I don't, I explicitly return `Ok(return value)` instead. If I want to introduce a new asynchronous value in js, I explicitly call `new Promise`. And so on. What's not visible in a do-block is the implementation of control flow. Which is fine, because this isn't the code that controls it - `Ok(Err(x))` is reduced in exactly the same way no matter what `x` is or where it came from. Traditional imperative code is the same way: the runtime system always works the same way, no matter which statements you ask it to execute. If you do choose to expose the underlying mechanisms of your control flow everywhere, you get continuation-passing style, which is useful in small doses but more or less impossible to reason about at scale.
- preseinger 3y agobad: first()?.second()?.third()? good: a = first() if a failed, handle that error b = second(a) if b failed, handle that error c = third(b) if c failed, handle that error yield c
- kaba0 3y agoExcept that without try-catch blocks you will have n separate control flow instead of a trivial to see pattern.
- preseinger 3y agohuh? it's exactly the opposite ideally, control flow goes 'down' via func calls, and 'up' via return statements this is the "trivial to see pattern" -- the code as written exceptions subvert those simple rules, they say any expression can potentially be a return statement, and recursively so!
- bvrmn 3y agoAnd what the point to make `if err {return err}` in most of cases? I've read a lot of code and error handling logic almost never in caller location.