Live data from Hacker News

Away from Exceptions: Errors as Values

humanlytyped.hashnode.dev

131–140 of 145 posts

Re: Away from Exceptions: Errors as Values

#131

Earlier quoted context omitted.

If I had to write that kind of boilerplate every time I had an artistic inspiration, I'd never ship anything! We are on far apart sides of a wide industry. I couldn't work productively in your dream language but hey, I'm happy we can have our different tools for our different needs. More power to us! :) > let the IDE suggest to you all of the possible exceptions So, programming without an IDE becomes untenable. I use…

I definitely agree that we're on the complete opposite ends of a wide spectrum of concerns and goals! > So, programming without an IDE becomes untenable. I use a text editor. It feels like you're shifting language features into the IDE. What's the difference between the compiler doing it automatically vs the IDE doing it automatically? I very much agree with this observation, but from the opposite side - for many dev…

Ohh, you could have dependency management built into the IDE (probably already do, I don't know). An integrated profiler could tell you how fast a function is as soon as you write it. I'm getting funny ideas.

What if the IDE worked with a distributed function database, rather than flat text files? Where you could browse (shop?) all the code written by others, by licence, performance, etc.?

Wonder if there are any programming streams/channels I could uh, spy IDE-based development from.

Re: Away from Exceptions: Errors as Values

#132

> Programming with exceptions is difficult and inelegant. Learn how to handle errors better by representing them as values. Funny how exception were invented because handling errors as values was considered to be tedious. And now, more and more languages are going backward.

More idiomatic error handling has appeared too. It's become a lot easier to bubble up errors with messages (e.g.: golang) without handling every single case.

Re: Away from Exceptions: Errors as Values

#133
post #128
post #124

Earlier quoted context omitted.

I guess we could extend Project Lombok to do this. You'll still have your "throws" statement but then the tool would wrap calls to catch those that are not listed in "throws" statement and wrap them as you say.

That'd be cool. It just occurred to me that I could probably do the same with attributes and DynamicProxy for C#. And also implement additional checks like "IF X is thrown, its properties must satisfiy some constraints.". (I program both in Java and C# these days.) Such "UnexpectedException" as I suggested would serve two purposes: 1) well, knowing that something unexpected happened and allowing you to handle it with…

But... both purposes 1) and 2) are already served perfectly fine with the current exception models already: you catch Exception at the very top-level in the "last chance handler", and if during testing an unexpected exception is thrown, it bubbles up past the existing handlers right into this "last chance handler". What does re-wrapping help with, exactly?

Re: Away from Exceptions: Errors as Values

#134
post #127

Earlier quoted context omitted.

There's no need for even that complexity. If base exception type had a single property, something like "CanRetry", all exception handling would be simple. Because when it comes to exceptions there are really only 2 things you can do: abort the current operation or retry it. The code generating the exception will know which of these is appropriate and the try/catch handler is what would restart or cancel the operation…

> If base exception type had a single property, something like "CanRetry", "Can retry" _WHAT_? This can work if you meticulously rewrap low-level exceptions into higher-level ones that reflect the high-level operation that failed. Concrete example: FileNotFoundException. I'd say that in "normal" circumstances it's not retriable: you're looking for a file, it's not there, so an exception is thrown. In "unusual" circum…

Where you handle exceptions has nothing to do with where they are thrown. You put your try/catch around whatever operation can be retried at the top level. I don't know why you'd need to rewrap exceptions -- I've never done that.

In that handler, you just need to know if the exception is fatal or a temporary issue for which retrying might succeed. If there was a CanRetry flag on the exception, that makes that determination easy without having to know every potential exception type.

Your FileNotFoundException is a good counter-example as maybe the called code is unable to know the intent. So, yes, in that case the handler has to make this determination based on the type (as we do now) or some code in the middle, that knows the intent, needs to catch and set that flag.

But most of the time one can determine at the point exception is thrown whether or not it's a potentially temporary situation (like a network error) or a unexpected fatal program logic error.

Perhaps "CanRetry" is too prescriptive of a name.

Re: Away from Exceptions: Errors as Values

#135
post #6

It's good to see so much focus on errors. They are essential when trying to build resilient systems. But our approaches are still very immature. First, to make it clear, this article appropriately points out that exceptions are still necessary and relevant. I disagree with some of the use-cases given, but it's important to recognize that exceptions should still exist in programming languages. Joe Duffy's article abou…

> when you start introducing other factors like how to report the errors publicly to a non-technical user, maybe in different languages, or whether to log it or send it who knows where, whether to trace or not, how, how to deal with duplicates or similar errors... I’ve tried searching for articles that talk about people deal with this in the context of web apps but have found it difficult to find content. It’s a tric…

Throw an exception.

In PHP we would throw LogicException on these cases, it should never happen thus it something wrong with your code (logic).

https://www.php.net/manual/en/class.logicexception.php

Then in your outmost function , like the main function, you capture it and report it with a error reporting tool like Sentry (so you are aware of it and can fix it).

And for the end user you would show a modal or similar to describe the error in user friendly way.

Re: Away from Exceptions: Errors as Values

#136
post #30

I'm firmly in the camp that believes that exceptions are a false economy. The post links to an "Exception Smells" post that doesn't mention one of my pet peeves: exceptions as control flow. For example, Java's parseInt [1] throws a NumberFormatException if the string can't be parsed. IMHO this is terrible design. As a side note, checked exceptions are terrible design. I wrote C++ with Google's C++ dialect where excep…

[deleted]

Re: Away from Exceptions: Errors as Values

#137
post #105

Earlier quoted context omitted.

> see what kind of trouble Java gives you, for example. I program a lot in Java, and the only trouble there is the lack of support for sum types and/or variadic type parameters in generics (i.e. to express functional interfaces that can throw an arbitrary number of checked exceptions, as a type parameter). That’s the only pain point for me and is something that could be fixed. In fact, the interplay with control stru…

I mean, syntactic sugar is one thing, but being entirely incapable of creating variadic exceptions really hamstrings you in places where you don't wish to write a great deal of redundant code for each combination of exceptions you may see.

Completely agreed about variadic exceptions, but that's not a drawback of exceptions, it's a limitation of Java's supported syntax for generics. In catch clauses, Java already has exception sum types (`catch (FooException | BarException ex)`), and Java also has variadic method parameters, so why not have variadic type parameters, maybe something like `Foo` that can be instantiated as `Foo`.

Re: Away from Exceptions: Errors as Values

#138
post #127

Earlier quoted context omitted.

> If base exception type had a single property, something like "CanRetry", "Can retry" _WHAT_? This can work if you meticulously rewrap low-level exceptions into higher-level ones that reflect the high-level operation that failed. Concrete example: FileNotFoundException. I'd say that in "normal" circumstances it's not retriable: you're looking for a file, it's not there, so an exception is thrown. In "unusual" circum…

Where you handle exceptions has nothing to do with where they are thrown. You put your try/catch around whatever operation can be retried at the top level. I don't know why you'd need to rewrap exceptions -- I've never done that. In that handler, you just need to know if the exception is fatal or a temporary issue for which retrying might succeed. If there was a CanRetry flag on the exception, that makes that determi…

> Where you handle exceptions has nothing to do with where they are thrown.

Funny you say this, when it's demonstrably NOT the case: a throwing method NOT wrapped in a try/catch will NOT have its exceptions handled at the call site. And vice-versa. If you want to retry a particular failing operation, you write try/catch around IT, not several levels up the stack.

You _could_ write it several levels up the stack IF you have precisely typed exceptions, therefore wrapping.

> I don't know why you'd need to rewrap exceptions -- I've never done that. [...] maybe the called code is unable to know the intent

To convey meaningful semantic information about the (business) operation that failed. Updating a record in the database can fail due to business rules (DB constraints), network connection that disappeared, concurrency conflict, transaction deadlock, etc. The user or higher-level code is not interested in the root cause, but in the actual consequence ("Could not update record". And yes, "IsRecoverable" flag, the value of which depends on the inner exception and its properties.).

And yes, the called code rarely knows the intent. There are a bunch of libraries out there being used in diverse contexts. So you catch and wrap the exception. Wrapping wouldn't be needed if library authors were careful about designing their exceptions, but I've rarely seen this to be the case. Even C# guidelines recommend you to use the generic, system-provided exceptions if an "appropriate one" exists. (IMO, a most terrible advice. And I discovered it was terrible by first following it then going back and designing "proper" exceptions for the system.)

> Your FileNotFoundException [...] needs to catch and set that flag.

But the exception type does not have that flag. So you have to wrap it in another exception. (Though all exceptions in C# have a Data field that is object -> object dictionary accessible to anyone. So you could use that.)

> You put your try/catch around whatever operation can be retried at the top level.

What is "top-level" for you? The shell's REPL loop? Exception blocks are non-restartable, so how would REPL continue the path-searching loop that threw FileNotFoundException?

> temporary situation (like a network error)

Ah yes, I love these. Someone pulled the power cable on some router the computer is indirectly connected to. To the program it looks the same as ordinary timeout error. How temporary is it?

Re: Away from Exceptions: Errors as Values

#139
post #138

Earlier quoted context omitted.

Where you handle exceptions has nothing to do with where they are thrown. You put your try/catch around whatever operation can be retried at the top level. I don't know why you'd need to rewrap exceptions -- I've never done that. In that handler, you just need to know if the exception is fatal or a temporary issue for which retrying might succeed. If there was a CanRetry flag on the exception, that makes that determi…

> Where you handle exceptions has nothing to do with where they are thrown. Funny you say this, when it's demonstrably NOT the case: a throwing method NOT wrapped in a try/catch will NOT have its exceptions handled at the call site. And vice-versa. If you want to retry a particular failing operation, you write try/catch around IT, not several levels up the stack. You _could_ write it several levels up the stack IF yo…

> If you want to retry a particular failing operation, you write try/catch around IT, not several levels up the stack.

Generally speaking when I retry and operation it's pretty far up the stack that I restart it. I'm not retrying sending a single byte, I'm retrying the entire file transfer operation (as an example). If it's batch job processing data in a loop, then the processing of each item is typically where I would catch and retry or ignore. If the exception actually said "I think you should retry" then it could retry otherwise it would abort.

> To convey meaningful semantic information about the (business) operation that failed.

Wrapped exceptions tend to provide less information than the root exception. I agree that library authors aren't as careful as they could be about exceptions and you might need to wrap an exception just to make it sane. Generally most libraries throw LibraryException and the real exception, with meaningful information you can action, is in the inner exception. I blame Java's checked exceptions for making that a thing.

> But the exception type does not have that flag.

Right. That's why I proposed it. "If base exception type had a single property... something like "CanRetry"... all exception handling would be simple."

> To the program it looks the same as ordinary timeout error. How temporary is it?

Never forget to put a limit of retries. You could get really clever and put an exponential delay on it.

Re: Away from Exceptions: Errors as Values

#140
post #128

Earlier quoted context omitted.

That'd be cool. It just occurred to me that I could probably do the same with attributes and DynamicProxy for C#. And also implement additional checks like "IF X is thrown, its properties must satisfiy some constraints.". (I program both in Java and C# these days.) Such "UnexpectedException" as I suggested would serve two purposes: 1) well, knowing that something unexpected happened and allowing you to handle it with…

But... both purposes 1) and 2) are already served perfectly fine with the current exception models already: you catch Exception at the very top-level in the "last chance handler", and if during testing an unexpected exception is thrown, it bubbles up past the existing handlers right into this "last chance handler". What does re-wrapping help with, exactly?

> it bubbles up past the existing handlers

Unless the method 1) throws an exception which it should not have according to its declarative contract (annotations in Java, attributes in C#), and 2) it gets (erroneously) handled by an intermediate handler.

> What does re-wrapping help with, exactly?

It makes it clear that the method broke its declarative contract, which is what exceptions are _for_. And given the restriction that only the runtime can throw such exceptions, you're sure that no other method can randomly throw such exceptions because... they like it so.

Post reply on HN