Live data from Hacker News

My philosophy of exceptions: they're always ambiguous (2021)

adamhooper.medium.com

1–10 of 46 posts

Re: My philosophy of exceptions: they're always ambiguous (2021)

#2
> So you think you know what an “exception” means?

An exception is when code can no longer do any meaningful work.

This could be because of a programming bug, unexpected input, network issue, hardware issue, etc. The cause doesn't really matter. What matters is that there is no way forward for the code.

And this is a decision that is made (or not made) by the programmer. In this author's Python example, he chooses accept the input as correct in the rest of the code. If a valid URL is not provided then the code cannot continue because it is assumed correct. One could easily change this code to have it continue; have it check for a invalid URL and reprint the prompt. However, this would be a different program with different requirements.

Re: My philosophy of exceptions: they're always ambiguous (2021)

#3
post #2

> So you think you know what an “exception” means? An exception is when code can no longer do any meaningful work. This could be because of a programming bug, unexpected input, network issue, hardware issue, etc. The cause doesn't really matter. What matters is that there is no way forward for the code. And this is a decision that is made (or not made) by the programmer. In this author's Python example, he chooses ac…

FWIW I didn't particularly like the article, but I really liked your comment. I think "an exception is when code can no longer do any meaningful work" is a great definition, and also explains why flow control with exception handling works the way it does.

Obviously there are gray areas re what it is to mean "code can no longer do any meaningful work", which is why there are decisions to be made about when to throw an exception or when to do something else. Usually, though, that "something else" is to return an error sentinel value, most often null or similar (e.g. "undefined"). And then I think the reason it's sometimes a tough call is that since null/undefined essentially means "empty", the APIs that most often return null do so in cases where you're asking for something and it's not there, so returning "empty" feels reasonable.

Re: My philosophy of exceptions: they're always ambiguous (2021)

#4
post #2

> So you think you know what an “exception” means? An exception is when code can no longer do any meaningful work. This could be because of a programming bug, unexpected input, network issue, hardware issue, etc. The cause doesn't really matter. What matters is that there is no way forward for the code. And this is a decision that is made (or not made) by the programmer. In this author's Python example, he chooses ac…

FWIW I didn't particularly like the article, but I really liked your comment. I think "an exception is when code can no longer do any meaningful work" is a great definition, and also explains why flow control with exception handling works the way it does. Obviously there are gray areas re what it is to mean "code can no longer do any meaningful work", which is why there are decisions to be made about when to throw an…

In .NET, they have 2 sets of parsing functions, "Parse" and "TryParse" for parsing strings into other types. The first throws an exception if it can't parse and the second returns a Boolean indicating success or failure.

Which function of these you use as a programmer is dependent on the context and it indicates your expectation. You might use "Parse" if you reading a well-defined file format where the string will always contain an integer and if it doesn't then something has gone horribly wrong. But you might use "TryParse" on user input where getting a non-integer is expected and you'll have to something about that other than error out.

Re: My philosophy of exceptions: they're always ambiguous (2021)

#6
I will paraphrase the Wikipedia definition (itself from Flaviu Cristian and John B. Goodenough):

Each procedure has a precondition, a set of circumstances for which it will terminate "normally". The set of "normal" circumstances is subjective and defined entirely by the programmer. An exception handling mechanism allows the procedure to "raise an exception" if this precondition is violated. The exception handling mechanism then specifies how the exception is handled.

Re: My philosophy of exceptions: they're always ambiguous (2021)

#7

My wish: people stop using the dumb line that exceptions are gotos.

The pattern for returning errors is something like the following pseudocode:

    main() 
    {
         (result or error) = functionA();
         if (error) die("There was an error: " + error);
         print result
    }

    functionA() 
    {
       (result1 or error1) = functionB()
       if (error1) return error1;
       (result2 or error2) = functionC(result1);
       if (error2) return error2;
       (result3 or error3) = functionD(result2);
       return result3;
    }

     functionB()
     {
         (result or error) = readFileAndGetResult()
         if (error) return error;
         return result;
     }
Exceptions simply automate the error returns; the same code with exceptions is merely:

    main()
    {
        try {
            result = functionA();
            print result;
         } catch (error) {
             die("There was an error: " + error);
         }
     }

     functionA()
     {
         result1 = functionB()
         result2 = functionC(result1);
         result3 = functionD(result2);
         return result3;    
     }

     functionB()
     {
         return readFileAndGetResult();
     }
The most naive implementation of exceptions would do exactly what the top code does. Check for an error result from the function and return it to it's caller until it finds a catch block.

The advantage of exceptions is that you don't get the bug that exists in functionA where it fails to propagate the error from functionD. It also makes the logic of the code much more readable and writable because you don't need to put an error guard around the call to every single function.

But what is telling is that, in both examples, the error is handled in exactly the same place in the code. How can one reasonably say the second case is like a goto but the first isn't?

Re: My philosophy of exceptions: they're always ambiguous (2021)

#8
post #4

Earlier quoted context omitted.

FWIW I didn't particularly like the article, but I really liked your comment. I think "an exception is when code can no longer do any meaningful work" is a great definition, and also explains why flow control with exception handling works the way it does. Obviously there are gray areas re what it is to mean "code can no longer do any meaningful work", which is why there are decisions to be made about when to throw an…

In .NET, they have 2 sets of parsing functions, "Parse" and "TryParse" for parsing strings into other types. The first throws an exception if it can't parse and the second returns a Boolean indicating success or failure. Which function of these you use as a programmer is dependent on the context and it indicates your expectation. You might use "Parse" if you reading a well-defined file format where the string will al…

Was this a workaround for frequent exception handling being too expensive on some platform? I like how Java lets some exception instances be reused without stack frames, so performance issues are less likely to compromise API design.

Re: My philosophy of exceptions: they're always ambiguous (2021)

#9
>>> When I shifted from Rust to Python, I tried to write matcher-style code. It wasn’t legible. I became irate.

so, in other words... rust developer tried to write rust in python, and it didn't work.

wasn't that the same story for each combination of two languages? I remember people criticize other people for "always writing java in any language they work with"...

Re: My philosophy of exceptions: they're always ambiguous (2021)

#10
post #4

Earlier quoted context omitted.

In .NET, they have 2 sets of parsing functions, "Parse" and "TryParse" for parsing strings into other types. The first throws an exception if it can't parse and the second returns a Boolean indicating success or failure. Which function of these you use as a programmer is dependent on the context and it indicates your expectation. You might use "Parse" if you reading a well-defined file format where the string will al…

Was this a workaround for frequent exception handling being too expensive on some platform? I like how Java lets some exception instances be reused without stack frames, so performance issues are less likely to compromise API design.

Semantically I think it's great. .NET has a bunch of these especially in LINQ.

A parsing failure isn't necessary an error. Sometimes it is, sometimes it's not. Even if exceptions weren't expensive, catching exceptions on all parsing (as you would in Java) is just ugly and, I would argue, not semantically correct. In my opinion, one should throw often but catch infrequently. Most of my large applications have a very small number of catches.

It's also perfectly reasonable to move this down a layer and have Parse return an Option type and choose to handle did-not-parse case or don't and let that trigger an exception.

Post reply on HN