News for hackers. Stuff that matters.
Re:Where Everything Went Wrong: Error Handling and Error Mes... by simiones on Friday February 19, 2021 @07:55AM (#26192608)
The biggest problem with that is that it is very unwieldly if you're using any kind of higher-order functions.

To fix that, you need to start supporting error polymorphism. For example, `map` should have a signature like

  map :: List a -> (a -> b -[err]) -> List b -[err]
So that

  map [1 2 3] +1 //no errors
  map [1 2 3] sendOnNetwork //returns NetworkError
At least, this is one of the major limitation of Java's Checked Exceptions idea, one which often forces you to use Unchecked Exceptions.

Another common problem is handling exceptions which occur while handling another exception. D has the best default I've seen in that area (it will automatically collect all of the errors, instead of panic()-ing like C++ or discarding the old exception like Java and C#).

Re:Where Everything Went Wrong: Error Handling and Error Mes... by dasyatidprime on Friday February 19, 2021 @11:56AM (#26195075)
There've been a few times I've used checked exceptions very locally in Java where I did use a type parameter successfully for this—though it's not really threaded through the type signatures in the standard libraries, so interop can be a problem. Almost like what you wrote, of course more verbosely, something like:

    interface SomeProcessor<E> {
        void process(Thing thing) throws E;
    }

    <E> void processThingsSomehow(
        SomeProcessor<E> processor,
        Container<Thing> things,
        Parameter how) throws E {
        // ... {
            processor.process(extractedThing);
        // } ...
    }
and then later:

    void processOrFail(Thing thing)
        throws SomeCheckedException {
        // ...
    }

    void processOurThings() {
        try {
            someObject.processThingsSomehow(
                this::processOrFail,
                getThings(), HOW);
        } catch (SomeCheckedException e) {
            // ...
        }
    }
and it definitely worked the way I expected—if the correct exceptions weren't caught in processOurThings, it wouldn't compile, and processThingsSomehow did not have to catch them. It even worked in at least some cases with multiple throws on the concrete SomeProcessor, though I think the different exceptions involved had an upper type bound within the package; I don't know how well that's handled in the general case.
Re:Where Everything Went Wrong: Error Handling and Error Mes... by simiones on Friday February 19, 2021 @12:58PM (#26195846)
Nice, I never actually tried to do this (my problem was more that I needed to use built-in functions that don't throw, for example sorting a list with a Comparator which can throw).
Re:Where Everything Went Wrong: Error Handling and Error Mes... by a1369209993 on Friday February 19, 2021 @09:39PM (#26200978)
> To fix that, you need to start supporting error polymorphism.

  > map :: List a -> (a -> b -[err]) -> List b -[err]
FWIW, Haskell has this already; it's called[0] Traversable:

  ghci> :t mapA
  mapA :: (Traversable t,Applicative f) => (a -> f b) -> t a -> f (t b)
  ghci> :t mapA @(Error ||) @[]
  mapA :: (a -> Error || b) -> [a] -> Error || [b]
0: The default prelude calls it `traverse` instead of `mapA` (which is terrible for reasons that should be obvious[1]) and `Either Error a` instead of `Error || a` (which is a matter of taste).

1: Especially if you rename the method of Functor from `fmap` to:

  map :: Functor t => (a ->   b) -> t a ->    t b
  -- for comparison:
  mapA :: ...      => (a -> f b) -> t a -> f (t b)
Re:Where Everything Went Wrong: Error Handling and Error Mes... by junke on Friday February 19, 2021 @10:35AM (#26194224)
And if the function can throw different kinds of exceptions, you need a way to express the union of unrelated exceptions (without defining a new variant type), a bit like Polymorphic Variants I guess.
Re:Where Everything Went Wrong: Error Handling and Error Mes... by dllthomas on Friday February 19, 2021 @04:39PM (#26198360)
Ideally also a way of saying "... except for X Y Z" while remaining appropriately polymorphic. I've remarked before that while checked exceptions help make sure you consider every possible situation, imprecision forces you to consider many (too many?) impossible situations as well.