Description
While exploring the Do notation implementation, I discovered that Ruby's throw/catch mechanism could provide a faster alternative to the current exception-based approach, particularly for failure-heavy workloads. I wanted to share my findings and discuss whether this would be a valuable addition to the library.
Context
The current Do notation uses exceptions (Halt) for control flow, which has the benefit of working seamlessly with database transactions (automatic rollback). However, I was curious whether alternative control flow mechanisms could offer better performance.
Benchmarks (Ruby 3.4.5)
I benchmarked three approaches:
- raise/rescue (current implementation)
- throw/catch (Ruby's non-local return)
- Fiber.yield/resume
| Scenario |
raise |
throw |
fiber |
| 3-step success |
554k i/s |
522k i/s |
321k i/s |
| Early failure (step 1) |
571k i/s |
757k i/s |
366k i/s |
| Middle failure (step 2) |
409k i/s |
529k i/s |
291k i/s |
| Late failure (step 3) |
343k i/s |
419k i/s |
245k i/s |
| Realistic operation failure |
405k i/s |
511k i/s |
277k i/s |
Proposal
I'm not suggesting replacing the current raise backend, it's valuable because it works with transaction blocks automatically. Instead, I'd like to propose adding an optional backend to use throw instead of raise and when using the throw backend, users would handle transactions explicitly in a base class.
So I would like to know if that's something you'd consider adding to the library? If there's interest, I'd be happy to submit a PR with the implementation
Description
While exploring the Do notation implementation, I discovered that Ruby's throw/catch mechanism could provide a faster alternative to the current exception-based approach, particularly for failure-heavy workloads. I wanted to share my findings and discuss whether this would be a valuable addition to the library.
Context
The current Do notation uses exceptions (Halt) for control flow, which has the benefit of working seamlessly with database transactions (automatic rollback). However, I was curious whether alternative control flow mechanisms could offer better performance.
Benchmarks (Ruby 3.4.5)
I benchmarked three approaches:
Proposal
I'm not suggesting replacing the current raise backend, it's valuable because it works with transaction blocks automatically. Instead, I'd like to propose adding an optional backend to use throw instead of raise and when using the throw backend, users would handle transactions explicitly in a base class.
So I would like to know if that's something you'd consider adding to the library? If there's interest, I'd be happy to submit a PR with the implementation