Hacker News new | past | comments | ask | show | jobs | submit login

While ROP is better than some current ways, I vastly prefer dataflow (pipes/filters) as a technique.

The fundamental problem, IMHO, with error-handling is the call/return nature of most of our programming languages. That means you have to return something from you function/procedure. If you have nothing to return (error) or nothing to return yet (async), you have a problem, particularly with intermediate functions that don't really know what happened below them and don't really have enough of the context from their callers to handle the error.

Exceptions allow you to skip the these intermediate layers. ROP makes you handle all those layers, but gives you some tools to help make sure you did it correctly.

Filters, on the other hand, do not return results. Instead they actively pass their results on to the next filter in line. That means that in the case of an error, they can do what functions/procedures cannot: simply not produce a result at all. The next filter will be none-the-wiser.

You can then have the filter have an out-of-band mechanism for actually dealing with the error, analogous to Unix stderr.




> The fundamental problem, IMHO, with error-handling is the call/return nature of most of our programming languages

I actually consider this a benefit, not a problem. The alternative, as I see it, is to side effect... which 99% of the time is a bad idea if there's an alternative.

> particularly with intermediate functions that don't really know what happened below them and don't really have enough of the context from their callers to handle the error

If you write a `map` function, you can use it in your pipeline to map over the Ok case and your intermediate functions don't need to know they're taking an Ok|Error type. This is exactly the same as what occurs in the `map`/`select` higher ordered function that's on the `list` type. The function passed to map/select doesn't know that it's being used on a list. In the same way, the function being passed to `Ok.map` doesn't know that it's being used on a discriminated union.

> You can then have the filter have an out-of-band mechanism for actually dealing with the error, analogous to Unix stderr.

To me this is a side effect and should be avoided. Basically your filter is partitioning your list into two lists, one of OKs and one of Errors, logging the errors, and then not reporting anything back to the consumer. LMK if I'm misunderstanding.


Well, I think you are filtering things through a lens that is so limiting that it might as well be misunderstanding. This lens, this filter, is so ubiquitous that as far as I can tell, most people can't recognise it. I call it The Gentle Tyranny of Call/Return [1][2][3]

> side effect... which 99% of the time is a bad idea

Nope. A filter does not have "side" effects. It has effects, as in what you want to achieve. And it turns out that having an effect is a good idea about 100% of the time, because otherwise your program is 100% useless. Now when your primary architectural style is call/return based, effects of the program that are not encoded in the return value do become "side" effects, but that's a limitation of call/return (which FP turns up to 11), not a problem of effects in general.

> > You can then have the filter have an out-of-band mechanism

> To me this is a side effect and should be avoided.

Why? Apart from the religious mantra of "it is a side effect"?

When I adopted this pattern, it turned out to be hugely beneficial. It keeps your happy-path happy, no need to pollute it at all with error handling concerns. And it lets you customise and centralise your error handling, which turns out to be what you usually want, but without the call-stack shenanigans of exceptions.

ROP kinda sorta attempts to do something similar, but due to the constraints of C/R, it turns out to be far more complex.

[1] https://dl.acm.org/doi/10.1145/3397537.3397546

[2] https://www.youtube.com/watch?v=Gel8ffr4pqw

[3] https://2020.programming-conference.org/details/salon-2020-p...


Scala has some nice containers around this with Either, Try, and Future. We’ve also made some custom hybrids like FutureEither. And then with basic for-comprehensions/maps you can chain together logic and if something fails it’ll return an either with a Left containing an error response, otherwise it’ll implicitly keep going with Right artifacts.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: