If your procedure does not run in a very tight loop, Exceptions for flow control in Ruby are fine - because they replace the Either. If you rescue exceptions according to their class (using matching of some description) you get a very good reproduction of an Either, much better than the approach with tuples of `[:ok, :result] and `[:error, :message]`. One of the unpleasant aspects of those tuples is that nothing prevents you from having a `[:ok, :error_message]` or a `[:error, :result]` creep in (say hello to the Go error handling). So I would do it with exceptions and a reduce - if your pipeline needs to be composable. If it isn't, maybe a straight-ahead `input = do_thing(input)` per line would be even simpler.
```ruby
calls = [
-> (input) { do_thing(input) },
-> (input) { do_another_thing(input) },
-> (input) { do_yet_another_thing(input) },
]
result = calls.inject("hello!") do |input_from_previous, callable|
If your procedure does not run in a very tight loop, Exceptions for flow control in Ruby are fine - because they replace the Either. If you rescue exceptions according to their class (using matching of some description) you get a very good reproduction of an Either, much better than the approach with tuples of `[:ok, :result] and `[:error, :message]`. One of the unpleasant aspects of those tuples is that nothing prevents you from having a `[:ok, :error_message]` or a `[:error, :result]` creep in (say hello to the Go error handling). So I would do it with exceptions and a reduce:
```ruby
calls = [
-> (input) { do_thing(input) },
-> (input) { do_another_thing(input) },
-> (input) { do_yet_another_thing(input) },
]
result = calls.inject("hello!") do |input_from_previous, callable|
That's a perfectly valid idea. I have always been nervous when using exceptions for control flow, if for no other reason tan their nonlocal nature makes it harder to reason about the code. I agree that in this case, if they are kept local to this one module, and always trigger an end of processing, they'd be OK.
As for the [ ok, :error_message ] issue, there's always Ruby's pattern matching...
There is, but I haven't really taken on to Erlang-style destructuring. It is amazing for deconstructing a network packet or a struct of fixed offsets, but using it as a dispatch mechanism... didn't stick with me.
Ah, there's come a moment when you'll suddenly find yourself writing more case statements with patterns than if statements. Not only does it linearize what could be a chain of `elsif`s, but it also lets you extract values that you need. Highly recommended.
If your procedure does not run in a very tight loop, Exceptions for flow control in Ruby are fine - because they replace the Either. If you rescue exceptions according to their class (using matching of some description) you get a very good reproduction of an Either, much better than the approach with tuples of `[:ok, :result] and `[:error, :message]`. One of the unpleasant aspects of those tuples is that nothing prevents you from having a `[:ok, :error_message]` or a `[:error, :result]` creep in (say hello to the Go error handling). So I would do it with exceptions and a reduce - if your pipeline needs to be composable. If it isn't, maybe a straight-ahead `input = do_thing(input)` per line would be even simpler.
```ruby
calls = [
-> (input) { do_thing(input) },
-> (input) { do_another_thing(input) },
-> (input) { do_yet_another_thing(input) },
]
result = calls.inject("hello!") do |input_from_previous, callable|
callable.(input_from_previous)
end
```
If your procedure does not run in a very tight loop, Exceptions for flow control in Ruby are fine - because they replace the Either. If you rescue exceptions according to their class (using matching of some description) you get a very good reproduction of an Either, much better than the approach with tuples of `[:ok, :result] and `[:error, :message]`. One of the unpleasant aspects of those tuples is that nothing prevents you from having a `[:ok, :error_message]` or a `[:error, :result]` creep in (say hello to the Go error handling). So I would do it with exceptions and a reduce:
```ruby
calls = [
-> (input) { do_thing(input) },
-> (input) { do_another_thing(input) },
-> (input) { do_yet_another_thing(input) },
]
result = calls.inject("hello!") do |input_from_previous, callable|
callable.(input_from_previous)
end
```
That's a perfectly valid idea. I have always been nervous when using exceptions for control flow, if for no other reason tan their nonlocal nature makes it harder to reason about the code. I agree that in this case, if they are kept local to this one module, and always trigger an end of processing, they'd be OK.
As for the [ ok, :error_message ] issue, there's always Ruby's pattern matching...
There is, but I haven't really taken on to Erlang-style destructuring. It is amazing for deconstructing a network packet or a struct of fixed offsets, but using it as a dispatch mechanism... didn't stick with me.
Ah, there's come a moment when you'll suddenly find yourself writing more case statements with patterns than if statements. Not only does it linearize what could be a chain of `elsif`s, but it also lets you extract values that you need. Highly recommended.