Live data from Hacker News

C++ Exceptions: Under the Hood (2013)

monkeywritescode.blogspot.com

91–100 of 116 posts

Re: C++ Exceptions: Under the Hood (2013)

#91

Earlier quoted context omitted.

> error handling and [exceptions are] not suitable for that I disagree :). Exceptions are fundamentally equivalent to "return sum type" error handling pattern. In an exception-enabled environment, you can imagine every function returning some Foo is really returning a {Foo, Error}. Then, every call like below, outside of try/catch block: value = SomeFunction(); is secretly translated to: maybeValue = SomeFunction();…

Obviously we can translate one Turing complete paradigm into another, but that's not very interesting. I argue that as so very often C++ the defaults are wrong . You can easily do the wrong thing, or you can go to a lot of effort to do the right thing, and since the right thing was technically possible C++ practitioners proudly declare C++ got this correct, and I say it did not. [See also: everything about const from…

I so feel the last point, and I'd like to add, that not having [as of now] any pattern matching really hurts when working with all sorts of sum types. Coming from Rust, something like `tl::expected` and `Result` feel like night and day.

Re: C++ Exceptions: Under the Hood (2013)

#92
post #44

Earlier quoted context omitted.

Well but of course! These functions are already implemented with basic exception safety in mind. What if they weren't? This is exactly the same situation as a function that has callback(); which cannot be changed into if Err(error) = callback() { return error; } because that would break some invariants. Changing return type from "void" into some "result" is a mechanical change.

As I already explained: RAII is pretty darn standard practice and guarantees basic exception safety in your own code too. The music is already there and people are already dancing to it. > What if they weren't? Obviously the language wasn't designed for rebels. The implicit understanding with tools is that you use them the way they're meant to be used. Only in that case do you get to assume you'll reap the benefits t…

There are interesting non-rebel cases of What if they weren't. I have a library (object only, no source) written for C (not C++) which wants callbacks. It is the only interface provided by the vendor for something that shall remain nameless. Every callback has to be wrapped in a try catch, or hell will break loose.

Re: C++ Exceptions: Under the Hood (2013)

#93

Earlier quoted context omitted.

> LibreOffice throws exceptions __a lot__ They're terrible for this. C++ Exceptions are a perfectly good exception mechanism, but what C++ programmers are trained to do with them isn't exceptions but error handling and they're not suitable for that. "I tried to create the file but it already existed" is an error - and now you're going to write the unhappy path code, this is the wrong place to have exceptions. "I trie…

I guess people's experiences are different :-) I find exceptions to be a perfectly fine error handling mechanism. I certainly prefer it to cluttering my code with explicit checks for return codes and such like.

returning errors doesn't have to have cluttered code. Just because Go messed it up doesn't mean it's bad.

Re: C++ Exceptions: Under the Hood (2013)

#94
post #26

Earlier quoted context omitted.

Can you describe your ideal error handling mechanisms? Or at least other mechanisms that feel more correct?

One technique I try first is to write code that cannot fail. For example, a sort function should never fail. Consider the case of running out of memory. One option is to pre-allocate all the memory the algorithm will need, then it can't run out of memory. Another option is to regard out-of-memory as a fatal error, not one that needs to be thrown and caught. Another example is UTF-8 processing. Early on, I did the obv…

IMO this is one of the advantages of the sum-type approach: the added friction of dealing with those explicit types and values encourages you to write as much code as possible that simply can't error in the first place

Re: C++ Exceptions: Under the Hood (2013)

#95
post #86

Earlier quoted context omitted.

No I'm quite aware of this. It's a restricted, implicit variant of it. But not also that it's not the type but the binding, which makes it slightly different from using a `Result`.

Hm. OK. I tried writing a response several times but I still feel confused. Can you explain what you mean by “not the type but the binding”? Note that I know the Haskell but not the Rust (guessing from the “Result” name) way of working in this style. (Not necessarily relevant or correct thoughts: - Your language still seems to mark potentially-failed values in the type system, even if it writes them T! not Either Err…

What I mean by saying "it's a binding" is that it is a property of the variable (or return channel of a function) rather than a real sum type. Consequently it does not participate in any type conversions and you cannot pass something "of type int!" because the type does not exist.

Here is an example:

    int! x = ...
    int*! y = &x;
    int**! z = &y;

    // If it had been a type then
    // int!* y = &x;
    // int!** z = &y;

    // int*! y = &x;
    // means 
    // int*! y = "if x is err" ? "error of x" 
    //                         : "the address holding the int of x"
This also means that `int!` cannot ever be a parameter, nor a type of a member inside of a struct or union.

The underlying implementation is basically that for a variable `int! x` what is actually stored is:

    // int! x;
    int x$real;
    ErrCode x$err;

    // int*! y;
    int* y$real;
    ErrCode y$err;

    // y = &x;
    if (x$err) {
      y$err = x$err;
    } else {
      y$real = &x$real;
    }

    int z;
    // y = &z;
    y$err = 0;
    y$real = &x;

The semantics resulting from this is different from if `int!` had been something like

    struct IntErr { 
      bool is_err_tag;
      union {
        int value;
        ErrCode error;
      };
    };
Which is what a Result based solution would work like. In such a solution:

    int! x ... ;
    int!* y = &x; // Ok
    int z = ...
    y = &z; // 

Re: C++ Exceptions: Under the Hood (2013)

#96
post #61

Earlier quoted context omitted.

The FPU does not include the source in the NaN, but that doesn't mean your own objects can't. What I do is have the error reported at the source, and then return the poisoned object. A better way would possibly be put the error message in the poisoned object, and report the error somewhere up the call stack.

I do that a lot with the firmware I write in C. typedef struct { err_t error; int error_line; char *error_msg; ... ... } thing_t; // set out of range error thing->error = THING_ERROR_OOR; thing->error_line = __LINE__; thing->error_msg = "outofrange" You can grep on 'outofrange' and find where the error was set. I originally started doing that to mark 'bad' analog readings in process control equipment. I wrote my filt…

I often using something like this in C++

    if( nullptr != pfnErrorSink )
        pfnErrorSink( "outofrange", __FILE__, __LINE__ );
    return E_BOUNDS; // Or sometimes throw E_BOUNDS;
Where pfnErrorSink is either global, thread_local or a field keeping C function pointer provided by whoever consumes the code.

Re: C++ Exceptions: Under the Hood (2013)

#97
post #85

Earlier quoted context omitted.

Is your work public? If my article was useful, I'd love to have a look at what you did!

It's public, but I doubt it still compiles against recent LLVM versions! I started it 8 years ago to get a better understanding how features like classes & operator overload would work in a JS-like language. It was really fun! https://github.com/castel/libcastel/blob/master/runtime/sour... https://github.com/castel/libcastel/blob/master/runtime/sour... I remember that at the time there were very few resources on pers…

ahhh, I see you got hit by some of the fallout of my migration from Wordpress to Blogspot. Sorry about that!

I tried to set http301s but gave up when I had to pay for it :)

Re: C++ Exceptions: Under the Hood (2013)

#98
post #84

Working with and implementing C++ exceptions for 30 years now, including implementing exception handling for Windows, DOS extenders, and Posix (all very different), and then re-implementing them for D, I have sadly come to the conclusion that exceptions are a giant mistake. 1. they are very hard to understand all the way down 2. they are largely undocumented in how they're implemented 3. they are slow when thrown 4.…

Who invented exceptions in the first place? Did they first appear in Java, encouraging C++ to imitate a java feature?

Software wise it seems to originate from Lisp[1].

[1]https://en.wikipedia.org/wiki/Exception_handling#History

Re: C++ Exceptions: Under the Hood (2013)

#99

Working with and implementing C++ exceptions for 30 years now, including implementing exception handling for Windows, DOS extenders, and Posix (all very different), and then re-implementing them for D, I have sadly come to the conclusion that exceptions are a giant mistake. 1. they are very hard to understand all the way down 2. they are largely undocumented in how they're implemented 3. they are slow when thrown 4.…

+1 plain old return error codes and the related modern status codes are the way to go. Lots of people say this is more work. I would your comment does a good job explaining why that work is immensely useful.

> plain old return error codes and the related modern status codes are the way to go

Why yes I just love to get a "Error one of the billion files this application tried to load wasn't available ErrorCode: ERR_MISSING_FILE_FUCK_WHO_KNOWS_WHICH". What I like about exceptions is that they make information that can't be encoded in a 32 bit integer value available to top level error handlers.

Re: C++ Exceptions: Under the Hood (2013)

#100
post #15

Earlier quoted context omitted.

What do you think of languages that use sum types for error handling, but can still unwind in a few scenarios? Reasonnable compromise, or should we get rid of all unwinding always? And if so, do we abort() or do we ask users to handle any and all possible errors.

I've read the proposals for it. It certainly looks good, yet exception handling looked good 30 years ago, too. I haven't used sum types myself, and often it takes years to discern whether things are really good ideas or not. What I personally use is the "poisoning" technique. This involves marking an object as being in an error state, much like a floating point value can be in a NaN state. Any operation on a poisoned…

You should give a serious try to sum types, btw. They're unambiguously good, and have been in use for the last 40 years at least. To me, not having them is an immediate disqualifier for a modern static language (along with some basic form of pattern matching that goes hand in hand with them).
Post reply on HN