At this point in my programming experience, I realize how spoiled I am to have exception handling available in most languages being used today (C++, .Net, Java, etc), at least in comparison to C. I am getting ready to take an advanced C course and has me really thinking those terms in comparison to my current paradigm.

In C, it's up to the programmer to prevent errors from ever occuring in the first place, which is quite daunting for anybody who is used to exception handling. It has occured to me that any language that I have come across that has exception handling happens to be object oriented. The first object oriented language to have exception handling, at least to my knowledge, is C++ which is sort of an evolution of C. (please correct me if I am wrong)

With that said, is there something about the object oriented nature of a language that allows exception handling, or was exception handling added as a feature as object oriented languages really started becoming a commonplace? What is that C lacks that to say, C++, in machine code that makes excpetion work?

I found this post about how exception handling works under the hood, but not sure how that information applies to my question (ie, does C lack notifications, continuations, etc?). Thanks in advance.

None of these exist, C is all that exists. Exception handling is just an abstraction. PS: Do you know about setjmp/longjmp?
–
sidyllDec 20 '11 at 18:05

2

I think your premise is a bit flawed. Standard ML has (by most definitions) exception-handling but not (by most definitions) OOP; likewise Ada before Ada 95. How many non-object-oriented languages have you used?
–
ruakhDec 20 '11 at 18:14

5

@MooingDuck -- OO languages don't "allow" stack unwinding any more than a potato allows cooking. Most OO languages require stack unwinding for one reason or another, and that facilitates implementing EH. But stack unwinding capability (ie, the ability to examine a call stack and discern the individual procedure boundaries) is a feature of the language support environment that may be present for other reasons (such as debugging, support of procedure scoping, etc).
–
Hot LicksDec 20 '11 at 18:30

3

@HotLicks: I like the potato analogy. More generally, OO languages do not require stack unwinding for exception handling; any language that has any kind of control flow requires that the continuation -- the "what am I going to do next" data structure -- be amenable to inspection and alteration. In many OO languages that data structure happens to be a stack, and therefore exception handling requires inspection of the stack. But there is nothing about OO languages that requires that a stack be used for the reification of continuation! OO languages can be stackless.
–
Eric LippertDec 20 '11 at 19:07

9 Answers
9

C lacks nothing in machine code, and exception handling was and is commonplace in C with setjmp and longjmp.

The reason for the complete lack of a language-level feature in purely procedural languages is that exception handling is identical to setjmp when no destructors need to be called. Exception handling has been around before in exotic languages, but never caught on because it was purely syntactic sugar. However, once destructors entered the scene and stack unwinding became necessary, language-level support became necessary and exception handling was widely implemented as part of the language.

I'm curious: how do C-style exceptions deal with cleaning up intermediary allocations? Even without full-fledged destructors, somebody's got to free that memory, right? Is it simply the responsibility of the calling function to ensure that allocations are not longjmp'd around?
–
Nicol BolasDec 20 '11 at 18:30

2

@Nicol: you can think of exceptions as being "purely syntactic sugar" for a combination of setjmp/longjmmp with so-called "exception frames". In C, you could create a per-thread linked list of structures. Whenever you hold some resource that needs freeing, and you want to call something that could "throw", you add a structure to the list, call the thing, then unlink the structure. When something "throws", it longjmps to whatever is at the end of the list, and that thing can free up the resources at that level and then longjmp to the next thing on the list...
–
Steve JessopDec 20 '11 at 18:41

1

... To "catch", you lay down an exception frame that when longjmped to, doesn't continue up the list but instead resumes execution at this level. That's probably the easiest way to implement exception-handling for yourself in C, if not the most efficient.
–
Steve JessopDec 20 '11 at 18:44

7

The way exception handling is handled in most C++ compilers, where the cost is at the throw side, cannot be mimicked using setjmp and longjmp. IN particular, calling setjmp forces a cost upon every try block even if an exception is not thrown. GCC in particular has an essentially zero-cost try at the cost of an expensive throw. I do not believe you can duplicate this in C at the language level.
–
edA-qa mort-ora-yDec 20 '11 at 18:49

2

@BlueRaja-DannyPflughoeft: at this point we're dangerously close to "structured programming is/isn't syntactic sugar for goto" ;-)
–
Steve JessopDec 20 '11 at 23:20

No. The two are completely separate. One can have OO languages that do not have exception handling as a control flow primitive, and one can have exception handling in non-OO languages.

Object-oriented programming, as Wikipedia helpfully points out, is a style of programming that emphasizes the value of abstraction, encapsulation, messaging, modularity, polymorphism, and inheritance in order to achieve low-cost code re-use and effective management of complex software projects implemented by large teams.

You don't see "loops" or "if statements" or "goto" or "try-catch-finally-throw" on that list because control flow primitives have nothing whatsoever to do with abstraction, encapsulation, messaging, modularity, polymorphism or inheritance being used to achieve low cost code reuse or effective management of complex software projects by large teams.

What is that C lacks that to say, C++, in machine code that makes exceptions work?

It is certainly the case that modern hardware is designed with exception handling as a control flow primitive in mind. C was designed long before that modern hardware existed, which would make it somewhat more difficult to implement exception handling in C that runs efficiently on all the hardware that C runs on.

But that said, there's nothing stopping you or anyone else from designing a new version of C that has exception handling as a control flow primitive, but without all the other features of C++.

If you're interested in the subject of how to add exception handling to non-OO languages that support continuations, see my article on the subject that sketches out the idea:

With that said, is there something about the object oriented nature of a language that allows exception handling, or was exception handling added as a feature as object oriented languages really started becoming a commonplace?

I first got to know exceptions when I had to learn Ada (studying CS) in the early 90s. IIRC, Ada had a special type Exception. It was, back then, not an object-oriented language. (Ada95 added some OO concepts.) However, I agree that stack unwinding (i.e. the complete automatic cleanup of allocated resources) is an important trait for the success of exception handling. Combining destructors with exception handling is an important point for the success of exceptions in C++.

I also seem to remember Stroustrup mentioning Ada as a major influence for exception handling in C++.

"stack unwinding is an important trait for the success of exception handling". In C++, that is. In Java you don't need stack unwinding, because you have GC instead.
–
Steve JessopDec 20 '11 at 18:15

+1 Right -- Stack unwinding was probably THE critical piece. Without stack unwinding you just had setjmp/longjmp, with no scoping of data or control, and exception handling was largely unmanageable, except as a global "panic" mechanism. With stack unwinding EH was pretty much "just a simple matter of coding". Whether stack unwinding was possible or not depended on the support environment for the language, and the call/return protocols involved.
–
Hot LicksDec 20 '11 at 18:17

6

@Steve: GC only deals with a single resource. It doesn't close your files and it doesn't release your mutexes. AFAIK you have to explicitly do this using finally. I consider this a regression from C++.
–
sbiDec 20 '11 at 18:18

@SteveJessop -- Sorry, that's total BS. Stack unwinding is just as critical in Java as in C++.
–
Hot LicksDec 20 '11 at 18:18

@sbi: whether that's a regression or not, it's no barrier at all to the existence of exceptions in Java. Exceptions as a language feature need some kind of resource cleanup, they don't need specifically the same kind of resource cleanup as C++. Without formal stack unwinding, though, the programmer ends up wanting finally instead, which does a similar job in a slightly different way.
–
Steve JessopDec 20 '11 at 18:27

You can raise your own exceptions too by calling RaiseException. Unlike setjmp and longjmp you can do your own cleanup in __finally blocks. In fact C++ exceptions are implemented on top of SEH (on windows).

This is an example of exception handling in totally object non-oriented way.

@Steve314: I don't think this is true. You need to access function's stack frame from inside except/finally to do anything useful, thus you need either compiler support or write everything in assembly (including the function body).
–
ybungalobillNov 20 '13 at 6:26

Having done some more reading, I now believe (but still don't know) that the language extension and API for SEH were written together as a unit. Given what the article I linked earlier says, it seems unlikely that the OS service could have been designed or used separately from the language extension.
–
Steve314Nov 23 '13 at 9:41

C by way of Unix signals: Unix kernel signals are derived from the Multics exception-handling facility

older versions of Lisp (granted, Common Lisp allows OOP, but it didn't when conditions and restarts were added) which apparently implemented conditions and restarts (unwind-protects) from ITS TECO — according to RMS (http://www.gsim.aoyama.ac.jp/~ida/GNU/RMStalk1207.html), implying that Lisp actually inherited exception handling by way of Emacs (nifty!)

It's a process-level analogue. Arguably both similar and different. One could potentially wrap a block of code by setting a SIGFPE handler with signal, in much the same way as a try {} catch (floating-point-error e) {}. en.wikipedia.org/wiki/… seems to share the idea of the analogy.
–
BRPocockDec 20 '11 at 19:43

It is a stretch to argue that setjmp/longjmp, and, even more so, Unix signals are "exception mechanisms", in the meaning of the term even by the time of Ada. Rather, Ada-style exception handling was in large part a reaction to/against schemes like Unix signals which were totally unstructured.
–
Hot LicksDec 20 '11 at 20:09

They all implement non-local transfer of control to a pre-designated entry point specifically designed to handle a type of unusual circumstance that interrupts the normal flow of code. As far as I can see, the rest is syntactic sugar on top of the basic concept.
–
BRPocockDec 20 '11 at 20:17

Well, if you consider it to be "syntactic sugar" that with exception handling the error handling code is inside the function that set up the exception handler and therefore has access to all [at least, all declared outside the scope of the try block] its local variables (i.e. the state that needs to be cleaned up), without forcing you to move that state to somewhere other than the stack.
–
Random832Dec 20 '11 at 20:38

For a non-imperative example, try Haskell on for size. Exceptions don’t even need to be built into the language; they’re just part of the return type (e.g., Either MyException MyValue, or ExceptionalT IOException IO String). Standard exceptions can be handled with the try function from the Control.Exception module:

Exception handling has been around for a fairly long time, well before C++. Several "boutique" languages implemented exception handling fairly early, but Ada (late 70s, IIRC) was probably the best known. Ada had glimmers of OO-ness, but was not OO by any modern standard.

Exception handling was also implemented in several versions of the PL/S languages (definitely not OO) that were mostly used internally to IBM. Early implementations (going back to the late 70s) were developed using macros (the PS/S macro processor was superior to most since), but later versions embedded EH into the language.

Well, exceptions are found within assembly language where you can use traps (forced exception) and other exceptions to control the flow of the program. An example would be a nullpointer or why not stackoverflow. There is nothing about the nature of OO-languages that enables exception handling. They just make it easier (and high-level languages have a tendency to throw a lot more exceptions). Exceptions is a key feature in basic programming. And by that I don't mean all programming, I mean "regular" programming, including assembly. I don't understand what you mean when you say "what is it that C lacks that to say, C++, in machine code that makes exceptions work?". And I wouldn't say that it is completely up to the programmer to catch exceptions in C (but I'm a novice in this area. If anyone can correct me, please do).