-
-
Notifications
You must be signed in to change notification settings - Fork 115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Should fallible stdlib methods return Option? #159
Comments
I'm a big fan of having two versions, like I would love for Grain to adopt a pattern where a function name that ends in But otherwise, I think for these we should have a version that throws and a version that returns an option. |
I'm not a fan of having an exception and option returning version of the same function. It definitely feels like "legacy" problems in the OCaml stdlib. As for |
This has been open for a while... I think I vote that they just return options. Thoughts @grain-lang/core? |
I'm not grain-lang/core, but I vote for options as well :) |
My preference is for options too. Forcing the programmer to consider all potential code paths is a good thing and has raised the quality of my team's code a huge amount. It can add a level of unwrapping overhead, but the alternative is unhandled exceptions in production. Having both forms I'm more ambivalent about - it frequently leads to code review arguments that the value being used has already been checked (e.g. array length and unsafe array access), but that can nearly always be recoded to remove the manual check and use the safe check version anyway. |
Strongly agree with returning if (some_vec.len() > 1) {
let item = some_vec
.pop()
.expect("we just checked that there's at least one element");
// ...
} This ends up working very well in practice: it means the normal path is the one that just checks the behavior, while giving end users an alternative which will blow up if they’re wrong… but they have to explicitly opt into it. There are times when this is the right thing to do, but because just using pattern matching or functional composition ( some_vec
.pop()
.and_then(|item| {
// ...
}); Rust (and Swift) also gives syntax sugar for working with optional types which is extra nice here: if let Some(item) = some_vec.pop() {
// ...
} This is a particularly good fit for a language like Rust or Swift which still supports (even encourages) an imperative style of coding for performance reasons, but it also means that in practice it's extremely rare that I feel the need to |
Also, seconding @phated’s notes about None of these would be directly applicable to Grain, as they emerge in the context of Rust’s fundamentally different design constraints—especially the need for zero-cost primitives here because of the key target of being a non-GC, high-performance language and its constraints around backwards compatibility as a stable language! But the Rust community has had a bunch of very good discussions about the tradeoffs between certain approaches to error-handling, so worth pulling on those threads a bit. I’ll also note that the Swift approach to both First, it layers in considerable sugar for As regards error-handling, Swift has both exceptions and (as of Swift 5) Then there are very rigorously-no-exceptions approaches like Elm’s, where everything is My overall preference is for exceptions to exist but to be effectively-uncatchable. This is (kind of) how panicking works in Rust: if you (There’s yet more to say on the design questions in that space as well: especially around things like how to layer |
Everyone has great points here! I remember us briefly talking about having Chris also made me remember to say this: since it'll be a little while before we've got first-class support for exceptions in WebAssembly, it makes even more sense to stay away from exceptions. |
Yeah, so I'm pretty much onboard with the things discussed here. If the stdlib uses Option and Result everywhere, it should become common place for end-users as well (often coding patterns are inferred from the stdlib). I think that we need some better utility in the language before we do that, such as |
I believe this is done now. There are some I also opened #464 to document these patterns. |
I was looking at some methods in
lists.gr
and noticed thathd
/tl
/etc have afail
call in them. Once #158 lands, do you think that these methods should be changed to return Options? I really appreciate that from stdlibs I've used in the past.The text was updated successfully, but these errors were encountered: