-
Notifications
You must be signed in to change notification settings - Fork 1
Use throw to implement Rust-like propagation #2
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
base: main
Are you sure you want to change the base?
Conversation
| assert_equal(R.err("err1"), result) | ||
| end | ||
|
|
||
| it "propagates the last try! ok" do |
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.
FYI, this test is deceiving. I think it's possible to do better, but this code actually just returns the result of the block, whatever that is. Since there's no runtime type checking of generics, I think you could just return an arbitrary Result from the block and there wouldn't be any type errors.
| def self.propagate!(&blk) | ||
| # TODO: using singleton class instance variables is obviously bad and not | ||
| # thread-safe but demonstrates how it might work. | ||
| @ball = T.let(Object.new, Object) |
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.
Though most examples online of Kernel.catch use symbols, it actually uses object_id to catch a thrown object. The block you pass to catch gets passed a unique object that is specifically intended to be thrown for this purpose, but it seemed imprudent to expose that object to the block that the consumer's of this library see, so instead this just creates a new Object so that it will only catch this specific object's object_id and consumer code can't accidentally early-return if they use throw inside the block for some reason.
|
Another idea I think would be possible using the |
|
A coworker pointed me to this article about why exceptions and |
|
Very cool stuff, thanks! I will take a close look and experiment whenever I can find some time. |
|
This is interesting! I actually had a less sophisticated version of this, with a Your version works better, and I like that it is context-aware: when called outside of a Using Having to wrap everything in an
👍 Yes, I've also thought the same and tried reading the Rust source for Thanks again for the contribution, and sorry it took me so long to reply! I must have missed the notification. |
This is just a quick spike that demonstrates the possibility of using
throwto implement Rust-like propagation (sort of) I wrote on a whim since I noticed in your README you asked for alternatives totry?, I doubt I'll be able to spend any more free time on it, but it's possible I'll be able to dedicate work hours at some point to make it "production ready" if this approach seems like something you'd want to adopt.Even with this change, I don't think the Result type actually works like Rust's
?in this case because in Rust (though I'm not an expert), theErrtype would be a union of all the possible errors, where this current implementation doesn't support that and I expect you'd have to use Sorbet's undocumented introspection methods to get a valid and comprehensiveErrtype, especially since there's no runtime checking of generics (which is probably why this test passes?).