-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
[stdlib] Add Result type #2749
[stdlib] Add Result type #2749
Conversation
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <110240700+martinvuyk@users.noreply.github.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Result
is definitely a useful type. I wouldn't eagerly create ResultReg
or ErrorReg
yet. In general, memory-only flavors of types are the way things are trending. If your counterexample is OptonalReg
, I wouldn't base future decisions off of that. That is used in a few load-bearing places internally that aren't easy to move to Optional
quite yet.
Given that, do you mind splitting out Result
and its tests into a separate PR? Any thoughts here, @ConnorGray?
ok that makes sense.
Yeah np, I can also just delete everything else from this branch since I already have it in another repo |
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Mojo already has errors and |
@remorses Optional is for when the function can only return a value or nothing, the information about what went wrong inside the function is lost. This is a pattern often used in python: try:
something()
except ValueError:
pass
except IndexError:
pass
... That is the same as returning a Result with different errors. If you still aren't convinced I suggest you have a look at Rust's Result and Option enums. |
The problem here is that in Python there is no way to handle an error in an expression, this is also the case for This becomes a problem when you want to assign a variable directly with the result of an The best solution here would be to add a way to create an expression out of a group of statements. Zig has something similar and Rust too, but usually you don't need them because most things in Rust are expressions and not statements. # with without anything becomes a way to turn a block into an expression
var result = with:
try:
something()
break "success"
except ValueError:
break "ValueError"
except IndexError:
break "IndexError" Same thing in Rust: let result = match something() {
Ok(_) => "success".to_string(),
Err(e) => match e {
"ValueError" | "IndexError" => "".to_string(),
_ => "other error".to_string(),
},
}; Created a proposal for this at #3093 |
That is a completely different discussion. And even then, it still needs a Result type to map to. With the current implementation one can do: fn func_that_can_err[A: CollectionElement]() -> Result[A]:
return Error("failed")
fn return_early_if_err[T: CollectionElement, A: CollectionElement]() -> Result[T]:
var result: Result[A] = func_that_can_err[A]()
if not result:
# the internal err gets transferred to a Result[T]
return result
# its also possible to do:
# return None, Error("func_that_can_err failed")
var val = result.value()
var final_result: T
...
return final_result but you have to know the string message inside the error beforehand if you want to do any condition based on that. I also have a proposal that I haven't formalized and I wanted to bring it up in the July 1 meeting that is having a parametrized pseudo-type for Error: struct Error2[T: StringLiteral](Stringable, Boolable):
"""This type represents a parametric Error."""
alias type = T
"""The type of Error."""
var message: String
"""The Error message."""
... with this result type one could do this fn do_something(i: Int) -> Result2[Int, "IndexError"]:
if i < 0:
return None, Error2["IndexError"]("index out of bounds: " + str(i))
return 1
fn do_some_other_thing() -> Result2[String, "OtherError"]:
var a = do_something(-1)
if a.err == "OtherError": # returns bool(err) and err.type == value
return a # error gets transferred
elif a.err == "IndexError":
return a # error message gets transferred
elif a.err: # some undefined error after an API change
return a
return "success" |
Hi @martinvuyk, thanks for taking the time to add this type, and think through what a A few comments on this PR:
Therefore, although I think its very reasonable for folks to point out that what's right for Rust may not be right for Mojo, I think this is the kind of moment where what's possible in this space isn't something anyone really knows for certain. And, consequently, the most positive path forward is to unleash some creativity and see what a Perhaps it won't pan out, but the community has got the brain power and the enthusiasm that I don't want to bet against them and make that experimentation more difficult by siloing away a proven-useful pattern like this. To that end, I suggest we:
Please let me know if you think this path forward sounds reasonable to you 🙂 P.S. regarding the language feature-related issues that @remorses was highlighting: I generally agree that this; the ergonomics for That's my hypothesis at least, but I wouldn't say that's a certain outcome 🤷♂️. Hence why I think the right thing for Mojo and the community is experimentation. We're all fortunate to be working on Mojo relatively early in its life, so experimentation and making mistakes is relatively low risk but potentially very valuable work to see what Mojo can do 🏎️ 🔥 🙂 |
That is a great idea.
We are still missing:
I understand, but I personally don't like finding out what kind of errors might come up only at runtime or only if the developer kept up with docstring best practices. Enforcing handling of every error type at compile time is one of the best things that Rust does IMO. I think |
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
Signed-off-by: martinvuyk <martin.vuyklop@gmail.com>
@ConnorGray would it make sense for this experimental namespace to be located in a repository Furthermore, some contributors like @martinvuyk clearly write code faster than the Mojo maintainers can review it. If we let the community take ownership of this new repository, we can share the review workload. Finally, it would be a good way to give more responsabilities to the community, who currently has a quite low "glass ceiling" (cannot become maintainers, cannot publish packages, cannot participate in stdlib's meetings, can only contribute to a delayed view of an internal codebase), without impacting the development of internal products. As the syntax is also changing, the work necessary to handle a breaking change in the Mojo syntax will be lower as we won't garantee that the nightly will always work with this To garantee that I think the biggest pains of this repo, from a contributors' perspective, come from the fact that internal code depends on it, which would not be the case for If you want to see examples of those kind of situations in the wild: TensorFlow had the exact same issue as Modular at the time, they made https://github.com/tensorflow/addons which had the source of truth in a public github repo, was managed by the community and it has been a huge success, contributing was much much much easier than in the TF repo. Sometime, the Tensorflow devs would grab a feature to make it "graduate", which is easier than starting a new feature from scratch. |
Add Result, a type modeling a value which may or may not be present. With an Error in the case of failure.
Closes #2748