Hacker News new | ask | show | jobs
by zeugmasyllepsis 1563 days ago
Curious, what is your argument in favor of a container over a type union to represent Result? As long as the type checking system forces users to refine the union to use the value and is aware of blocks of code within type guards (I've heard this referred to as "flow-aware typing" but I'm not sure if that's a standard term) then the advantage of an explicit Result type isn't very obvious to me. What am I missing?
3 comments

In terms of ergonomics, I'm more a fan of the fluent style [1] over flow-aware typing with guard blocks. I've never heard of till not but I presume you mean that's like where you have like

    foo: Optional[Foo]
    if foo is None: 
        return some_error_handler()
    bar = foo.qux()  # the above guard "upgrades" O[Foo] to Foo

For me the real reason I love the ergonomics of the Rust-style "monads [2]" over Unions is that it lets you generically operate on each of 3 orthogonal parts: the value, the error, and the container. Optional or Union[T, E] don't quite hit the same way because you end up having to do more contortions to deal with managing the happy path vs sad path. What ends up often happening is without a container, your type "leaks" into other methods - you start ending up with functions that expect a Union[SomethingMoreSpecific, E], instead of just letting the Result.map(T->U) handle it.

Also specifically in Python, the type system is kind of weak (especially those bundled with Pycharm), and a lot of functional operations which ought to be more strongly typed end up with their types erased for whatever reason. In particular functools.partial seems to discard type information more than I'd like. The Result python package [3] doesn't run into this problem near to the same degree.

1] https://martinfowler.com/bliki/FluentInterface.html

2] I find this term frustrating not only because it's infamously ineffable, but also because there appear to be disagreement whether Rust's containers are actual monads or not, leading me to dub what I call the "Engineer's Monad" which is a generic container you can map and flatmap over, even if isn't strictly an Applicative.

3] https://pypi.org/project/result/

None != Error would be my beef with it. Sometimes I'm expecting a NoneType in the happy path.
Tagged Unions (“containers”) vs. simple Unions is basically about composability.

You can't emulate Result[Result[T]] with a simple Union.