(11-14-2009, 05:10 AM)zenogais Wrote: [ -> ]A decent article, but I had just a few things I would like to know more about if you don't mind. You said in your post that "Conditional checks are one of the slower operations on almost any CPU design". To perform a conditional check you need merely check whether or not all the bits in two given bit sequences are equal. As far as I know most modern CPUs use a simple XNOR based approach that scales quite nicely and is extremely fast. Just wanted to double check and see if they were really slow, as I'm not very familiar with many facets of modern CPU designs.
The slow part is the branching instruction that is typically paired with any conditional check. In rare cases a conditional's flags can be used directly without branching, although that is certainly the exception, and not a rule (and some CPUs don't have any flags at all, eg MIPS).
On the P4 a typical branch instruction was some 20 cycles on average, compared to 1-3 cycles for just about everything else. Best case was 2-3 cycles, worst case 59 cycles. Most AMDs have a 2-3 cycle branch prediction hit result, and a 17-23 cycle miss, compared to 0.5-2 cycles for just about everything else. Core2's are better with roughly 2 cycles for hits and 11 cycles for misses, although they also have an extremely high number of instructions in the 0.33 to 1 cycle count. So any way you slice it, branches are much slower than most other commonly used instructions.
Furthermore, the performance of branching hinges heavily on the Branch Prediction Cache built into any modern CPU. The cache is of limited size, so the more branches you have for a repetitive section of code, the
slower your average jump instruction will become for that code. Thus the speed it compounds on itself.
Yeah I'm aware of all the drawbacks of exceptions. In general I find the excuses against exceptions to be right on one sense, but mostly irrelevant in the grand scheme. The code cleanup one is a C programmer's fear, and is totally meaningless to a proper C++ programmer who uses objects for cleanup (same thing any decent C# programmer *must* do always, for example, although it's possible that Google hates C# too). It's an old way of thinking. Furthermore, tons of code out there doesn't do proper cleanup anyway, when encountering errors. The implicit (non-)cleanup of exceptions hardly makes it worse.
Quote:* More generally, exceptions make the control flow of programs difficult to evaluate by looking at code: functions may return in places you don't expect. This results maintainability and debugging difficulties. You can minimize this cost via some rules on how and where exceptions can be used, but at the cost of more that a developer needs to know and understand.
Omg. Flow control evaluation is a ridiculous claim. In modern threaded applications, which must rely heavily on messages and callback events, flow control is
effing hard, period. Even if exceptions made it worse (and they absolutely do not), they would be the least of the programmer's worries. The flow control for the PCSX2 gui is impenetrable right now because it A. manages a couple threads, and B. it needs to synchronize a lot of actions and dependencies between them. In order to do so without risk of rendering the gui completely unresponsive to the user for long periods of time (or forever, if a thread deadlocks for some reason) we have to execute a whole lot of tasks on threads so that the GUI thread typically remains free to process GUI messages, and then tie the completion of those tasks to "event listeners" that update program states and execute the next task in the job. Anyway, exception handling makes this much easier to manage, because I have one single error handler at the GUI message pump, and nearly every possible "recoverable error" (I call them runtime errors, which mimic's STL's naming convention) propagate into that single
catch block (errors from GUI or threads alike). From there I have the proper thread affinity needed to pop up modal dialogs (which feed the user an error and request a response), re-check all the various program states (and a full recheck is always needed, because with so many threaded, message driven tasks I can't really make any assumptions safely), and then re-dispatch new messages to respond to the user's request related to the error.
Without exception handling, I'd have ~1500 more lines of code in the new wxgui for PCSX2, most of which would be designed to check for and propagate a myriad of errors up the thread callstacks and across threads in a fashion that would be able to transmit relevant error information to the main GUI thread for display to the user. And I'd have to include manual cleanup for hundreds of objects, all of which are currently handled safely and implicitly by C++ object destructors. So yeah, the flow control argument is only true for kozy coders who've only had to work on nice linear uninterpretable algorithms that only return a possibility of 1 or 2 errors. (in which case yes, using exceptions is pretty pointless -- man wish I could be so lucky).
Quote:Turning on exceptions adds data to each binary produced, increasing compile time (probably slightly) and possibly increasing address space pressure.
Interesting, but applies to GCC only. Structured Exceptions supported by MSVC and Intel C/C++ have no such penalty. Unfortunately they're under patent by Borland currently, but that'll expire eventually, in which case everyone will have access to minimal-overhead SEH exceptions that can safely throw across almost any type of stackframe. I do wonder if Google's anti-exception rant is more to do with their hate of patents and Microsoft in general, and less to do with actual programming justifications.
Quote:The availability of exceptions may encourage developers to throw them when they are not appropriate or recover from them when it's not safe to do so. For example, invalid user input should not cause exceptions to be thrown. We would need to make the style guide even longer to document these restrictions!
Whine, whine. Show me a programing language that can be used to write compact and modularized code and I'll show you a programming language that an idiot coder can abuse in a hundred ways to make entirely obfuscated code. Hell, the worst code I've ever had to try and read only used the most basic forms of C/C++ syntax and did not break a single basic tenant of the typical modern style guides. But it was still horribly written, had twisted redundant logic patterns, and no underlying structure in spite of what appeared to be, on the surface, a structured API. That code didn't even use the ternary ?: operator, for which many "style guide" people like to whine about to no end as well.
Point is, this is what programming is all about. you're given tools and you need to be educated on how to use them. If you're given a hammer and a screwdriver, and if you pound a bunch of nails into a wood board at random then you're Fail as a coder. Fine. If someone then gives you a power saw and you proceed to lop off your arms and legs, that doesn't mean we need to make power saws illegal. It means we should probably make sure you don't re-contribute your gene pool to the next generation of human beings. But that won't happen either. Exceptions are a power saw. They're really good at cutting through the meat of error handling. And yea if you're not using the table guard, you're going to probably bleed to death on the ambulance on your way to Coder Hell. But that won't get much sympathy from me.
I will point out two real drawbacks of Exceptions, that Google missed in their stereotypical anti-exception zealot rant:
* C#'s exception structure
SUCKS. By that I mean the way it defines and uses it's exception object types. It provides for no easy way to isolate Logic Errors (typically considered programmer errors, or debug assertions) from Runtime Errors (typically safely recoverable, such as file/stream errors). In fact, I don't think Logic Errors should be exceptions at all. They should be debug-build assertions, and should result in program failure in non debug builds (typically there is no "safe" recovery from any logic error, regardless of how robust your app is. Once a program encounters a logic error it's a safe bet the app's internal data structures have been compromised). That's a case of Microsoft making a gross error in the design of their error handling, and has nothing to do with the merits of exception handling itself. The same thing could be done in any API by providing poorly designed error codes, and not properly checking for and handling logic errors.
* Exceptions can complicate 3rd party API "upgradability." Although this actually applies to most object-oriented APIs, and not excpetions specifically. That is, it's more a side-effect of the "benefits" of strict typing, object encapsulation, and the complications in retaining compat up the tree of such object hierarchies. All of these things effect exceptions (which are objects) much like any other object. So if you realize your exception model is busted (like C#'s is), you're screwed for finding a nice way to fix it that won't force rewrites of existing code wanting to upgrade to the new lib.
[edit: and this was a big reason why, until recently, many 3rdparty libraries didn't embrace OOP]
... of course moderm programming has fixed THAT too, since it's becoming ever-more commonplace for "side-by-side" versions of shared libraries. This is made possible by the mass storage available these days, and basically library authors say "if you want the old APi, use the old code, kthx." and that too, is a good thing, where the overall progress of software design and technology is concerned. But I'm sure a lot of coders find reasons to ***** about it too.