core
core copied to clipboard
Feature Request: Option::or_return_none()
It seems like this README.md is out-of-date: https://github.com/moonbitlang/core/blob/34096f4e37269777274b3ed6a2eed499890ae030/option/README.md?plain=1#L45-L72
It says:
Ending expression with
?will automatically unwrap theOption, if the result isNone, it will return early from the function.
AND YET... THIS WAS ONE OF MY FAVORITE MoonBit FEATURES that was eliminating so much ugly boilerplate code like this: https://github.com/gmlewis/moonbit-pdk/blob/40948f7d08128b4c36036276d9489f32be8e99db/examples/add/add.mbt#L7-L19 which reminds me of Java in a really bad way.
So I would like to make a feature request for Option::or_return_none() which would allow that same code to be written like this:
pub fn Add::from_json(value : @json.JsonValue) -> Add? {
let value = value.as_object().or_return_none()
let a = value.get("a").or_return_none().as_number()
let b = value.get("b").or_return_none().as_number()
...
}
Unfortunately, this feature request may require compiler support, without which it might not be possible to write.
You could try to use some monadic functions ( bind/flatten ) to alleviate this issue.
pub fn Add::from_json(value : @json.JsonValue) -> Add? {
value
.as_object()
.bind(
fn(value) {
let a = value.get("a").map(Json::as_number).flatten()
let b = value.get("b").map(Json::as_number).flatten()
match (a, b) {
(Some(a), Some(b)) => Some({ a: a.to_int(), b: b.to_int() })
_ => None
}
},
)
}
You could try to some monadic functions (
bind/flatten) to alleviate this issue.
Sorry, but that seems to me to be even harder to read than my current workaround.
Why not use json pattern?
pub fn Add::from_json(value : Json) -> Add? {
match value {
{ "a": Number(a), "b": Number(b) } => Some(...)
_ => None
}
}
Thank you, @Yoorkin , I will in this case.
But I would still like this feature request to be considered because there are myriad opportunities to take advantage of this in non-JSON-related code.
...Or simply bring back the ?. Seriously.
hi @gmlewis we will add features like this which is more general and readable:
guard let Some (x) = expr else { return None }
guard let (Some (x), Some(y)) = (a,b) else { return None}
guard let pattern = expr else { raise (Failure("xx")}
let v = a?.b?.c?.d // optional chaining
The ? was removed because the implicit non local control flow transfer generally makes code hard to reason about, we want to keep such things minimal