Live data from Hacker News

Errors and Exceptions

giantfublog.wordpress.com

41–50 of 55 posts

Re: Errors and Exceptions

#41
post #35

Earlier quoted context omitted.

How about using an algebraic effect system? That's sort of a general purpose alternative to monads that also doesn't require an extra code path, and adds a bit of theoretical niceness. For example, if your code can throw two different exceptions, composing two monads is order-sensitive (because the monad interface is in some sense too general and forgets too much), while algebraic effects always commute with each oth…

True. I could rephrase as "the possibility of errors is just another type, and is best treated as such"?

[deleted]

Re: Errors and Exceptions

#42
post #40
post #31

Earlier quoted context omitted.

I think it's more a product of application complexity. The deeper the waters below you, the less you can meaningfully do with errors triggered by our actions. The closer you are to the hard boundary with the outside world, the more easily you can enumerate error conditions and be complete. A server connected to a network socket is very close to the wire protocol, and the potential error states are fairly well known a…

I like this distinction. It makes sense to me based on my experience, and as an extra bonus, explains the passion on both sides of the debate. If you don't have both kinds of experience, obviously one is strictly better than the other, it just varies as to which one that is. Both sides look at the other in horror and ask "Why are you trying to ruin my programs?", with good justification.

I think part of it is that when interacting with the outside world, error states are not an unexpected return value. Network cables get disconnected, packets get lost, hardware breaks, things time out, etc. There are inherent races because the external world is concurrent; you can't grab something and then be assured that nobody else will mess with it.

Higher up the stack, it's more likely you're dealing with an abstract object of some kind with no direct correspondence with the outside world. Exceptions are more likely to be an unexpected state, where unexpected means an unexplored area of the state space owing to an increased number of moving parts.

Re: Errors and Exceptions

#43
Some interesting discussion here.

First of all it seems that some people are still having a bit muddled vision about what is an exceptional error/condition. Of course you will need to first define what constitutes an exceptional situation in your application and its domain. The blog post used a file opening as an example. That example implied that in that software, in that particular context we have a requirement that our file must be opened. If for some reason it cannot be opened we have grounds for an exceptional condition. When we have this condition we then choose some particular method/means for how to indicate the situation and how to deal with it.

We can also demonstrate this the otherway around. Someone mentioned as an example something like a (web)server. Obviously in that application's domain not being able to open and serve some file is just a part of the normal flow. Clients may make request to resources that do not exist. So in that example that would not be an exceptional circustamce but the "FILE NOT FOUND" condition is just part of the normal conditional flow of the program.

However in that same server we might be for example reading the initial configuration file when the program is started and if we fail to open the file then we might have grounds for an exceptional situation.

So to sum this up, what constitutes an exception situtation is all up to the domain of the program. The blog post discussed methods for dealing with that situation. This is an important point to realize.

Finally a note on assert, yes there are cases when you can't hard fail and core dump on assert as much as you would like to. For example when implementing API's that define error return values for "hard failure" conditions. Whether this is sensible practice and makes the software world better or worse is a matter for another discussion.

Re: Errors and Exceptions

#44
post #34

Earlier quoted context omitted.

How is that different to option 2?

It has nothing in common with 2. It's an extension of 4 where the eventual (dynamically scoped) handler is executed on the non-unwound stack and may unwind the stack (same as an exception), perform an action on the non-unwound system (e.g. resume, resume with a value provided, resume with a restart specified, repeat, etc…) or dynamically opt to resume looking up handlers.

I have to disagree. Historically, conditions and restarts came from Multics and PL/I. There is also similar thing in IBM z/OS, descendant of MVS (ESTAE recovery routines). When ESTAE is invoked, you can decide where you want to recover (since it's assembler you may unwind stack if you have one), or you can "percolate", which means to pass processing on the next error handler. Unix signals is probably another descendant. So in the 1960s, recovery by error handler (the option 2) was very common thing. It only got a bit forgotten later due to them not being properly supported in C, so it didn't get into C++ and Java due to cultural disconnect.

Re: Errors and Exceptions

#45
No discussion of errors and exceptions could be complete without including Erlang (/OTP)! How does its philosophy of fail fast and rely on your supervisor to restart fit into 1-4? I've been dabbling in Elixir lately, and I really like how easy it makes writing the "happy path", while still robustly handling errors.

Re: Errors and Exceptions

#46
post #22

Earlier quoted context omitted.

Strong type system with a good support of checked exceptions would tell you what kind of exceptions can arise from every function call. If you don't check them in your function code, they would add to the list of exceptions that your function can throw. It would basically turn every function you write with return type T into Either with syntax sugar that would transfer exceptions between calls so you don't have to sp…

With this scheme you would end up with pretty bad problems regarding function pointers and lambdas. Because the type is deeply implicit, you would have two function pointers that look compatible but are totally incompatible. Then when you want to assign them to a variable -- how do you know a priori what type to declare the variable?

This would seem to be "just" a matter of correctly handling polymorphism along yet another axis.

Let's say we had the following C++ code:

    int foo(int (*bar)(char), int (*baz)(), char c) {
        try {
            return bar(c)
        } catch(SomeException &e) {
            raise otherexception;
        }
    }
What exceptions can be raised by foo?

The answer is simply computed - "anything raised by its first argument except SomeException, plus the type of otherexception".

Such a system would be tremendously more flexible than Java's checked exceptions, while still allowing you to confidently restrict what might be thrown in a section of code.

Re: Errors and Exceptions

#47
post #27

Earlier quoted context omitted.

Go read one of Herb Sutter's "Exceptional C++" books. Okay, just read the first one. If you don't close the book and reflect, "I am never writing this shit," Herb didn't do his job. Writing exception-safe code in C++ is very hard. Depending on another module's authors to get their C++ exception handling right is the road to madness. In the example above, the FAILED clauses clearly handle all the failures. In the exce…

If you don't close the book and reflect, "I am never writing this shit," Herb didn't do his job. The same Herb who said Prefer to Use Exceptions to Report Errors ? (which makes no sense btw, just like saying to never ever use them) Depending on another module's authors to get their C++ exception handling right is the road to madness. Wait, so we should just forget about STL/boost/.. and reinvent all wheels? Or maybe…

"you are checking if HR is FILE_NOT_FOUND or FILE_NOT_ACCESSIBLE but suddenly the author changed the name into FOOFILE_NOT_FOUND and now you wind up changing a hundred places in your source code"

Not weighing in on the broader discussion (in this comment), but more languages support exhaustiveness checking of case statements than of exceptions.

Re: Errors and Exceptions

#48
post #14

Earlier quoted context omitted.

> Much of the trouble with error returns comes from the strange C convention that functions with return values can be called as if they didn't return a value. The "warn_unused_result" GCC function attribute makes the compiler emit a warning when you do `func(something);`: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attribute...

The problem is it needs to be applied to every function that returns a value. And I'm pretty sure you can't apply it to C library functions. Gcc seriously needs a global flag for this.

You might be surprised at the warnings you'd get. Did you know, for example, that printf returns a value? It's also a return value that rarely, if ever, tends to be useful.

Re: Errors and Exceptions

#49
post #14

Earlier quoted context omitted.

The problem is it needs to be applied to every function that returns a value. And I'm pretty sure you can't apply it to C library functions. Gcc seriously needs a global flag for this.

You might be surprised at the warnings you'd get. Did you know, for example, that printf returns a value? It's also a return value that rarely, if ever, tends to be useful.

As a joke, in case you are really paranoic about error handling, you might end up with this :-)

    int written = printf("Got here");

    if (written != sizeof("Got here") - 1) {
        written = fprintf(stderr, "Could not print my sacred message\n");

        if (written != sizeof("Could not print my sacred message\n") - 1) {
            exit(I_DONT_KNOW_WTF_IS_HAPENNING_HERE);
        }
    }

Re: Errors and Exceptions

#50

Earlier quoted context omitted.

You might be surprised at the warnings you'd get. Did you know, for example, that printf returns a value? It's also a return value that rarely, if ever, tends to be useful.

As a joke, in case you are really paranoic about error handling, you might end up with this :-) int written = printf("Got here"); if (written != sizeof("Got here") - 1) { written = fprintf(stderr, "Could not print my sacred message\n"); if (written != sizeof("Could not print my sacred message\n") - 1) { exit(I_DONT_KNOW_WTF_IS_HAPENNING_HERE); } }

That sort of thing is actually a completely valid approach.

You made a small mistake, since fprintf and printf call the same underlying code, the error handling should be either log the error in any way still available, and then depending on the design of the whole program, exit or continue. If printf fails you know exactly what is going on or have to exit. ( And printf would be wrapped in a function if you plan to use it repeatedly. )

Post reply on HN