I think exceptions are very bad idea. Not nearly as bad as implicit nullability but comparable. Hacky emulations of exceptions... Well I don't want to be near such code.
But that was interesting read non the less, thanks OP.
I agree it was an interesting read. Haven't thought about setjmp and longjmp in many years.
>> I think exceptions are very bad idea.
There are many cases, API implementations for example, where I cannot think of a better solution. Packing result codes into returned data, using return values, using global state, using passed state buffers, all those approaches are worse, imo, and lead to less readable and maintainable code. What's your preferred alternative?
In Haskell I use Maybe's, Either's and their ilk (packing result code in returned data I guess?), in C - your usual boolean return values like this:
bool parse_literal (ParsingState* state, LiteralValue* pResult).
In Java/C# I have to use what other people are using :)
My dislike of exceptions (as well as errno and Set/GetLastError) is due their masking, hiding error conditions and situations. And I prefer everything to be stated clearly. Including error handling code (answer to 'did I handled all possible failures of calling this?' should be instant).
Unfortunately proper error handling is hard, nearly as much as 'naming things' :)
> longjmp() and setjmp() are tricky. They’re obscure, can give rise to subtle bugs, are highly platform-specific, and, if abused, will probably lead to awfully confusing code
Actually, being part of the ISO C standard, they are not platform-specific. Otherwise, just use C++ where destructors take care of cleanup when an exception is thrown.
Everybody has access to C++ now. Even on the Arduino. If you need exceptions, go to C++. "longjmp" was a bad idea when it was first invented, and it hasn't improved with age.
Yet whole applications are written around it and they work perfectly well. Not saying that is an argument that it is somehow a good idea, just that while it might looks bad, it also works ok when done properly.
That's circular reasoning. The objection is that it only works well in certain circumstances. Mostly in fairly simple applications with either small teams or rigid conventions to enforce clarity and prevent bugs.
If "done properly" implies "works ok", then it's circular reasoning.
I'm not sure your example is a counterexample either. Implementing part of a fairly simple runtime (like Lua's) using longjmp is an example of a good use of longjmp, in my opinion.
I've seen longjmp used in a number of fairly large projects, with diverse teams. E.g. postgresql.
If abstracted away they don't necessarily cause that many problems. Sure, it'd be nicer if there were a better alternative, but often there's just none. And no C++ isn't always an alternative. Many older platforms have only horribly bad C++ compilers, certainly not ones where you want to rely on exception handling.
As if longjmp and c++ exceptions are the only two ways to go. How about return codes? Or error out parameters? Not so bad to work with if you be consistent about the style...
When I went for a job interview at Symbian many years ago for a position working on Symbian OS, they told me (and it's obvious from looking at their documentation) that they implemented thier own execption mechanism in C++ using setjmp and longjmp becuase they deemed that the C++ execption system was too slow. Other accounts say that the exception mechanism wasn't present in the language at the time, which I am not sure of.
This is why you had to push all local variables onto a clearnup list in each an every function, this I think, from memory was a call to CleanupStack::Push with a wrapper macro.
If indeed they did this becuase exxceptions were 'too slow', then the problem, im my option would be that they were using exceptions far too much -- as status indications and so on. They are, again, in my option a great help used in the right way, with the C++ RAII idiom, which is essential in the face of exceptions.
I actually wrote a JSON parser for fun and profit 2 weeks ago. It's mind blowing to me how his code is similar to mine. I wrote mine completely from scratch. I even called my routine `parseValue`. Once one has a look at the JSON grammar, writing a parser for it is trivial.
Exceptions are not about going from one place to another. It's about unwinding the stack properly and calling the destructors of variables on the stack. This is not a close emulation at all.
While I'm not saying this is a good idea, you can combine a pool allocator with longjmp exceptions to get an approximation of unwinding. It requires that you are very careful about structuring your code, but I once wrote a whole web server this way: http://git.annexia.org/?p=rws.git;a=tree (using: http://git.annexia.org/?p=c2lib.git;a=tree ).
To be serious: This was my first thought, too. Exceptions are essentially one kind of monads, and any complex compiler or interpreter could make good use of more types of monads.
I believe the paper of Wadler makes this most clear. Some time ago, it was a real eye-opener for me:
But that was interesting read non the less, thanks OP.