Slashdot Mirror


The Scourge of Error Handling

CowboyRobot writes "Dr. Dobb's has an editorial on the problem of using return values and exceptions to handle errors. Quoting: 'But return values, even in the refined form found in Go, have a drawback that we've become so used to we tend to see past it: Code is cluttered with error-checking routines. Exceptions here provide greater readability: Within a single try block, I can see the various steps clearly, and skip over the various exception remedies in the catch statements. The error-handling clutter is in part moved to the end of the code thread. But even in exception-based languages there is still a lot of code that tests returned values to determine whether to carry on or go down some error-handling path. In this regard, I have long felt that language designers have been remarkably unimaginative. How can it be that after 60+ years of language development, errors are handled by only two comparatively verbose and crude options, return values or exceptions? I've long felt we needed a third option.'"

86 of 536 comments (clear)

  1. The third option by Anonymous Coward · · Score: 5, Funny

    Ignoring the error completely, data integrity or planned functioning be damned.

    1. Re:The third option by MacDork · · Score: 2

      That's still catch blocks:

      try { throw VeryImportantException(); } catch (VeryImportantException e) { throw UnimportantException(); };

      You'd never do this on purpose, but its rather easy to accomplish in practice.

    2. Re:The third option by Yetihehe · · Score: 4, Interesting

      That's the philosophy of erlang, "Let it crash". Apparently this leads to some of the most reliable systems. http://www.erlang.org/download/armstrong_thesis_2003.pdf
      Apparently OP didn't heard about it, because this is the third way.

      --
      Extreme Programming - Redundant Array of Inexpensive Developers
    3. Re:The third option by pla · · Score: 4, Insightful

      You'd never do this on purpose, but its rather easy to accomplish in practice.

      You have too much faith in humanity, friend!

      I hate hate hate the exception-handling model of dealing with errors, because in practice, I've seen very, very little code that actually handles the error. People either:
      1) Use far too coarse grained a "try" (as in, on the entire function), giving almost no possibility of knowing what actually happened or how to recover,
      2) Use the "catch" just to tell the user "golly, it broke, try again later" rather than accidentally revealing the ugly (but meaningful) exception text,
      3) Assume nothing in the "try" could actually fail and only do it to satisfy their company's code auditors, so the catch does... nothing, or
      4) (My "favorite") - copy the entire body of the "try" into the "catch" and blindly do it again!

      When used correctly, exception handling doesn't make your code cleaner, it reduces to a slightly more verbose way of checking return values. You should, if you want any hope of really dealing with the error, wrap every call in its own try/catch. I have not ever seen that done (and honestly, I can't claim I do it as religiously as I should either - I tend to trust my own code (big mistake), and only do that for external calls).


      Then again, how do you handle the system volume suddenly vanishing out from under you? So, perhaps the coarse-grained "golly, it broke, try again later" folks have the right idea. ;)

    4. Re:The third option by Nerdfest · · Score: 5, Interesting

      I've gotten to prefer using runtime exceptions with a general policy of "Throw as early as possible, catch as late as possible". Only catch if you can do something about it. It works very well, and keeps the code very clean.

    5. Re:The third option by PRMan · · Score: 2

      Ignoring the error completely, data integrity or planned functioning be damned.

      This is the option chosen by most developers...

      --
      Peter predicted that you would "deliberately forget" creation 2000 years ago...
    6. Re:The third option by Anonymous Coward · · Score: 5, Informative

      Sounds to me like you actually hate abusive exception handling. Exceptions that are in relevant places and handle the errors in meaningful ways are good. I've seen lots of code that actually handles the error, but then I work with competent people (and yes, that is a lovely thing).

      Exception handling can make code cleaner. I'd much rather see a nice exception than return value checking as I can instantly see what kind of error is expected and what should happen if it occurs.

      Please don't dismiss a step forward from return value checking just because you're unfortunate enough to have never worked with anyone who uses it properly.

    7. Re:The third option by Simply+Curious · · Score: 4, Insightful

      I would say that it is much less verbose in the case where errors need to be propagated upward. This is exactly why not every function call has a try/catch around it. Suppose I am writing a function that accepts a filename, interprets the text in the file, and then returns some modified version of the text. With error codes, I would need to explicitly check that open_file has returned a valid file handler. I can't do anything without a valid file, so I then need to propagate the error upward. On the other hand, with exceptions, I could simply not catch that exception from open_file. I can't do anything to recover, so I should let the exception propagate upward to wherever called me, and then let them deal with it.

    8. Re:The third option by mrvan · · Score: 5, Insightful

      I think you are focussing too much on java-style compiler-forced error handling. To me, the essence of try/catch error handling is that you only catch errors if you can deal with them. If you can't (the majority of cases), let is escalate, all the way up to the user (or a log file) if needed. I think there are three sane ways of using a try/catch: (1) to actually deal with the error (this is by far the rarest), (2) mainly in loops of more-or-less independeny actions: to log the error, reset state, and continue working, and (3) at the top level, to log the error and display something less meaningful but less scary to the end user.

      I think it is a bad design decision to impose static checking on declared 'throws' statements, because that forces routines to catch stuff that they can't handle, or declare a meaningless list of everything every called routine could ever throw. In essence, it couples the signalling and handling again that exceptions were supposed to decouple.

      Another nicety of exceptions compared to return values is that the semanitcs of "something went wrong" is clear. This makes it possible to e.g. have a wrapper function that begins a transaction and commits or rollbacks it depending on the outcome (e.g. https://docs.djangoproject.com/en/dev/topics/db/transactions/?from=olddocs#django.db.transaction.commit_on_success)

    9. Re:The third option by Capitaine · · Score: 5, Interesting

      My work implies writing aeronautical software specifications. In order to facilitate FAA/EASA certification of the system, we are required to stick to the KISS principle. Data validity checks are done almost everywhere, but we are asked to design the logics so that they do not need to use these data validity statuses. Degraded mode is done through the use of failsafe values. The consumer of a data do not need to know the status of the producer. The whole system is designed so that it works and is robust with minimal use of alternate logics.

      This principle works well with dataflow oriented program and might be adaptable to other domains.

    10. Re:The third option by Sarten-X · · Score: 4, Insightful

      If you're actually seeing #4 in practice, your coworkers need a nice bit of physical re-education.

      Each situation you describe has perfectly valid circumstances:

      1) Using a "try" on the whole function is suitable on functions where a particular caught exception can only mean one thing. If you're catching a FileNotFound exception, it means the file's missing. It doesn't matter that the error happened while opening the file, or at the first read. The exceptional situation is that the file can't be found. Exactly which call had the exception doesn't matter beyond debugging (for which there's usually extra information in the exception, such as line numbers).

      2) Revealing ugly text isn't user-friendly. Rather, it shows that the programmer has no idea what's going on and is putting the burden of debugging on the user. Ideally, the exception handler will first take steps to remedy the situation on its own (config file not found? Use sane defaults and save them for next time!), then log the exception somewhere with only the meaningful parts (such as a module name, line number, and a selection of parameters). Nobody really needs to know the whole stack trace up to main().

      3) Sometimes, an empty catch routine is fine, and if it isn't fine a good code audit should notice this anyway. Some errors can be safely discarded, but the code should reflect that they are being willfully ignored, rather than just ignored out of ignorance.

      4) Despite my glib comment earlier, there are also cases where blindly retrying a step is the cleanest solution. One example I've seen recently is where a database connection would reveal a timed-out disconnection only upon actually executing statements. The straightforward solution was that if the first statement failed due to a timeout, the connection (which was now in an error state) would be checked again, reconnected, and the statement would be retried.

      You should, if you want any hope of really dealing with the error, wrap every call in its own try/catch. I have not ever seen that done...

      ...because it's a silly idea. Now you're just using exceptions as special return values. Exceptions are not supposed to mean "something went wrong here". They should mean "there's a situation that is so unexpected that I don't know how to handle". It's a different paradigm entirely. The idea is that rather than writing your program to anticipate every possible error (as the mathematicians so loved), the program should instead follow a more practical "hope for the best, plan for the worst" design. Rather than worrying about exactly which byte of a file couldn't be read, the program should just understand that something's wrong with the file, and its contents can't really be trusted.

      Then again, how do you handle the system volume suddenly vanishing out from under you? So, perhaps the coarse-grained "golly, it broke, try again later" folks have the right idea. ;)

      If your program is supposed to run on transient resources (like, for instance, a cluster that has a weak master controller running your program, and the bulk of its processors scheduled to run computation), this should be expected. Perhaps a "system vanished" exception can be raised to signal that in-process calculations should be restarted the next time the system appears, and that previous calculations should be saved in case everything else disappears, too.

      Or in other words, it broke and you should prepare to try again later. :)

      --
      You do not have a moral or legal right to do absolutely anything you want.
    11. Re:The third option by SplashMyBandit · · Score: 5, Interesting

      In Java you probably wouldn't do as you say. You would 'chain the exception; so that the original exception information is preserved even though you are transforming the exception type (eg. from a checked exception thrown from a library to an unchecked exception you don't have to declare throws clauses for). The code becomes:

      try {
      // Do something here that may throw an exception (which is 'checked').
      // eg. throw Exception();
      } catch (Throwable th) {
      throw new RuntimeException("A problem occurred when launching the SS-18 because the launch authorization code was invalid. The launch authorization code had a value of " + authCode, th);
      } finally {
      // Do any clean-up.
      }

      There are two import things to note in this contrived example:

      • * The use of the chained exception. When the exception type is transformed by the creation of the new exception we include the old exception in the constructor. That way the 'chain' of exceptions can be viewed and the original cause of the exception found. That will help you fix this issue.
      • * A message that tries to describe the exact decision used to throw the exception and the values of any contributing variables or boundary values. It is critical this information is recorded at the point of throwing because in a massively multithreaded system with millions of transactions you can't reproduce the same conditions exactly in your debugger. The only information you have is what you put in your log, and you must include all relevant information in that log. Otherwise you will not have enough data to diagnose the decision the program made to throw, and won't have enough info to fix the problem.

      Checked exceptions are valuable in Java. Those that are against them don't understand that they are very useful for certain classes of problems - systems that have to be reliable. The mistake the Java designers made was that they made the library throw checked exceptions rather than unchecked ones. If they had used unchecked exceptions everywhere (while still supporting checked exceptions for systems that need to force reliable operation under error conditions) then many of the gripes people have when encountering Java would be eliminated. Plus, programmer productively would increase because we wouldn't have to wrap and chain the checked exceptions produced by library calls all over the place. C# kinda gets it right in the fact the libraries don't have/use checked exceptions, but it lacks the option of using checked exceptions in critical systems. So neither Java nor C# have it perfect, IMHO.

      If you are a Java developer writing libraries intended for re-use by others then you should ensure your library never throws a checked exception to the caller. Only libraries for critical systems should do this. Unless you are working on nuclear plant control, avionics, medical devices, weapons systems or interplanetary probes then your system probably doesn't need to expose checked exceptions.

      The way you structure, handle and report exceptions is mundane, but is absolutely crucial for writing reliable and easily maintained software. Most programmers are sloppy about this, or consider it as unimportant as good documentation, but that is what makes then bad programmers (if you ever have to use or maintain their software).

      I hope this helps some developers out there understand how to use chained exceptions. The chaining *preserves information* about the cause of a failure. The adding sensible messages and program state is also about *preserving information* about the failure at the point of throw. Loss of information is what you are battling here, since once you lose/throw away information it is a huge effort to reconstruct it later. Avoiding loss of information is worth keeping that in mind as you develop, so you avoid doing it. Example: the built in NullPointerException being the worst example of providing zero additional information about what was null, a problem if you have multiple chained method calls on a single line. Don't write code like the Java code that raises NullPointerException.

    12. Re:The third option by Z00L00K · · Score: 2

      And you can only catch errors if you know that they will appear.

      One example is when developing in C# you never know which exceptions to except unless you waste a lot of time reading the documentation for every class that you use or resort to do a general catch of Exception and try to guess what's best to do. In Java the amount of "blind" exceptions thrown are limited to the Runtime exceptions that you can get - which is bad enough, especially if some esoteric third party developer throws their exceptions as extensions of the RuntimeException.

      Exceptions are all good and fine but sometimes it's good enough with a return value of zero when an empty string is converted to a number. Even classic Basic had a crude exception handling in the "On Error Goto" statement. But every time you have an error you need to do some cleanup or take an alternate path. Just continuing blindly will give you a bad headache.

      Catch and re-throw has it's uses too, but it shall be used with some care. It may be useful when you run a client/server solution where you don't want to expose every exception up to the client since the client may then need to link third party libraries that you don't want the client to carry. Especially if there are two vendors, one on the server side and one on the client side.

      --
      If builders built buildings the way programmers wrote programs, then the first woodpecker would destroy civilization.
    13. Re:The third option by cyber-vandal · · Score: 2

      Microsoft code is littered with technically correct but utterly useless error messages. Key not found in dictionary is another annoying one when it's thrown in code that you don't have the source for like CRM 2011. Which key would that be then? One of the 25 that I've just passed to you. Oh ok I'll just remove each one until the error no longer happens, that's a 21st century solution *rolls eyes*.

    14. Re:The third option by west · · Score: 5, Funny

      I have not ever seen that done

      I have. The coder handled every possible exception intelligently, handled the possible exceptions in the exception handlers, handled the possible exceptions in the exception exception handlers, etc. It was phenomenal. His code could practically handle a CPU burning out at the same time as the primary disk had been hit by lightening while the database had been accidentally converted into EBCDIC.

      Unfortunately, it was also completely unmaintainable. No human being, outside of the original programmer, could possibly grok all the conditions, sub-conditions, and contingencies. The code was also 3000 lines of error handling for about 25 lines of normal execution.

      It was my privilege to gaze upon the world's most complete error handling before I fulfilled my responsibility of burning it to the ground.

    15. Re:The third option by Yetihehe · · Score: 2

      Significantly - you don't (typically) catch exceptions in erlang. You plan what to do after some process fails.

      --
      Extreme Programming - Redundant Array of Inexpensive Developers
    16. Re:The third option by Tough+Love · · Score: 2

      lease don't dismiss a step forward from return value checking just because you're unfortunate enough to have never worked with anyone who uses it properly.

      +1. An exception mechanism is absolutely necessary to being able to contruct sane error reporting and recovery in a nontrivial code base, without unduly obfuscating the code. Whether this powerful tool is used or abused depends on the the quality of the programmer, as nearly every aspect of software development does.

      One issue with exception handling: you generally lose the ability to get a traceback at the point of throw. So it is often difficult to find out where an exception came from. This can fairly be regarded as a flaw in the language implementation: there should be a way to tell the compiler to always generate a traceback before the throw. Or better, there should be an easy way to capture the traceback as, say, an array of strings, that can be logged or stored in the exception object. In absence of a facility like this, I typically add a macro to generate a trap to the debugger at any throw point where the call chain is not immediately obvious. Then there has to be a way to turn that off in production code, and then the ability to know the call chain for an exception in production code is lost. It's very much an unresolved issue. Funny, I haven't seen any of the language gods take note of this important point.

      --
      When all you have is a hammer, every problem starts to look like a thumb.
    17. Re:The third option by BitZtream · · Score: 3, Insightful

      You're fired.

      unless you waste a lot of time reading the documentation for every class that you use

      Again I say, you are fired. I would throw you out on your ass so quick it would make your head spin if you told me that as one of my employees. If you aren't reading the documentation you don't know how the method works and you don't need to be writing code.

      That is the most idiotic argument I've ever heard. Its the definition of bad programing, ON PURPOSE no less.

      --
      Persistent Volume manager for Kubernetes - https://github.com/dwimsey/openshift-pvmanager
    18. Re:The third option by TapeCutter · · Score: 2

      An exception mechanism is absolutely necessary to being able to contruct sane error reporting and recovery in a nontrivial code base, without unduly obfuscating the code

      The one thing that exceptions offer that return values don't is they allow the programmer to forget about the stack unwind and assume someone else will catch it higher up the chain.

      Useful yes, "absolutely necessary" no. I can't think of a faster way to kill a non-trivial code base than to try and convert it from one error handling method to the other. The stack trace problem is one reason many commercial source trees avoid exceptions (particularly C/C++) code. There is nothing worse than finding a tree with thousands of files and the only error handling is a try/catch around the main loop. The only real difference between the two is how they unwind the stack. My personal preference is the return code method since the writer is forced to think about the stack unwind at the time of writing.

      No matter which way you do it, handling errors adds time to writing the code. Not handling errors adds even more time to maintaining the code. Also in a commercial setting error handling is often insufficient when there is a real bug in a complex production environment, you also want fine grained tracing that the customer can turn on and then send you the logs. Again this takes an investment of time, but IMHO, good trace logs that are easy for the customer to configure are far more useful for debugging problems than error messages.

      --
      And did you exchange a walk on part in the war for a lead role in a cage? - Pink Floyd.
    19. Re:The third option by geminidomino · · Score: 2

      Exceptions are not supposed to mean "something went wrong here". They should mean "there's a situation that is so unexpected that I don't know how to handle"

      Wait, but when you write an exception handler for it, then it's not only expected, but you know how to handle it, so it's not an exception anymore, so the program doesn't know how to handle it, which means...

      ARGH.

      Exception: Out of Stack Space. System Halted.

    20. Re:The third option by AmiMoJo · · Score: 4, Insightful

      What a douchbag you are. In the real world there are deadlines and never enough people on hand, so you don't have time to read every bit documentation for everything. That is perfectly acceptable as long as you are still capable of developing software that is robust and does what the customer wants.

      This is why we have testing. It is more cost effective to avoid getting bogged down in making something perfect and instead get it tested as you go, making improvements based on feedback. The only people who do it any other way are writing mission critical code that costs a fortune to develop.

      You know what? You're fired. Your products are all late, way over budget, the development team hates your anal retentive attitude, while your competitors left you in the dust.

      --
      const int one = 65536; (Silvermoon, Texture.cs)
      SJW, n: "Someone I don't like, and by the way I'm a fuckwit" - AC
    21. Re:The third option by west · · Score: 2

      I did the essence of this with much less code.

      Not "the essence" - *an* essence. A mere shadow of this error handler.

      You and I might be content with "recycle" and a sad little notification in an error log somewhere, but not this error handler.

      When it detected the CPU was failing, it would comb the register for life signs, route around the dying CPU, say last rites, mournfully bury it, and continue on its mission (as well as sending an email to accounting to order a new CPU). If the disk drive had been hit by lightning, it moved fast enough that it would outpace the bolt traveling down the electrical cord, rewire the junction box to send it current into the ground, power up the secondary backup drive, and send a work order to building maintenance to repair the malfunctioning lightening rod on the building's roof.

      The database being converted to EBCDIC? Hah! The error handler converted it to Armenian, just to show it could, before converting it Aramaic, then English, then Unicode, and then sending an email to project manager to let him know he could remove the Unicode phase in our legacy database update project.

      The error handler's philosophy was clear and built for an earlier age that even then, realized that man would in time become a lesser, diminished being, incapable of understanding the intricacies of exactly how the error should be recovered. As such, it did not depend upon the fallible hands of men to repair an unexpected error condition. It simply handled them *all*.

      Alas, even the programmer, in his wisdom, could not foresee the changes that would one day occur, and for those of us who held but a hundredth of the knowledge that he had accumulated in his years of service, we could no more alter his code than a gorilla could rebuild a finely tuned Swiss watch.

      And so his code was lost to the knowledge of men (except the revision control system).

      I'm sorry. All you have there is good, maintainable, effective program.

      What we had, and then threw away, was art made code.

    22. Re:The third option by SplashMyBandit · · Score: 2

      My example was intended to be more representative of real code where you chain exceptions.

      What now? Only call private methods in catch and finally? Wrap everything in a second try block? That's turtles all the way down

      Yes, avoid having overridable methods in cleanup. The same applies to constructors (a principle you may be more familiar with). I do use a second try block if I have to. Generally I catch, log in full, and then supress clean up errors; they are not significant to the operation of the program. At the end of the clean up catch I re-throw the original exception, because that is the exception that matters.

      "Turtles all the way down" is a possibility but I've never seen more than two exceptions deep in practice. IMHO the problem wih most programs/programmers is they don't look for potential exception causing problems early enough. If you code is thoroughly unit/integratation tested there are only two conditions that can then cause your program to fail:

      • 1) bad input data, or
      • 2) resource failure of some kind (bad disk, bad network, out of memory etc).

      Bad data
      The bad data is easily handled by checking preconditions of your program: validating all input data at the point it is received, read from file/database/network (throw IllegalArgumentException here); also checking preconditions before use that combinations of data that were not actually bad are consistent and the operation you are about to perform will not fail due to the data it is given (throw IllegalStateException here). If you look for bad data *before* you make any modifying operations you can roll back to a consistent and safe state easily. Your cleanup is often trivial because you detected the issue before you modifed state, not half-way through.

      Resource exhaustion
      Resource exhaustion can happen at any time, the best thing to do there is go back to a safe state (consistent data) and try and release resources. Thn try again. If you can't release resources then you have to abort the operation or abort the program. If you log the problem in a very clear manner some wetware can come along and correct the environment before trying again. This is why I mentioned good messages in logging is so important.

      Safe states
      We all know that the operations of software transistion the system from state to state. In a well-tested system any state that is attempted can fail for either of the reasons I pointed out: bad (insufficient or contradictory) data, or environmental/resource problems. The important thing is that if the attempted operation fails and the transition is aborted then the system is returned to a consistent state. In almost all cases this can be achieved by ensuring that the needed resources and data are acquired before any writes are made. It is not always the case this is so, but it very often is. Because this is true the "turtles all the way down" rarely happens (well, hasn't on any of the huge projects I've been on). More importantly, the existing constructs we have are more than sufficient in the vast majority of cases. Yes, you occasionally get nested catches but this is quite rare in my experience (programs doing millions and millions of transactions with all interconnects with all sorts of external devices and systems).

      Things developers can do
      So, what we can do as developers is:

      • * unit and integration test with good coverage
      • * validate all input data at the point we receive it (we can't use it until it is validated)
      • * check preconditions that before we attempt any operation we have sufficient and consistent data, plus have acquired any required resources (files, memory, network) as much as we can
      • * assume our operation can fail for any reason, and try and recover back to a consistent/safe state. Autorecovery is an often an option (eg. automatically re-attempting a network or database operation in the failure is likely to have been due a transit
    23. Re:The third option by SplashMyBandit · · Score: 3, Insightful

      I agree, C# is a nice language. The failure of C# is that *the libraries* are not cross-platform. Note that the Mono libraries are not used by the majority of C# developers, and the Mono libraries are incomplete compared to the Microsoft ones, and will never be complete according to the Mono roadmap.

      With the world becoming more and more heterogenous with regard to CPU (ARM & x86/64), Operating System (Linux, Android, Mac, Windows) and environment (embedded, rich client and web) then cross-platform matters more than ever.

      The language benefits of C# over Java do not compensate for the massive superiority of Java for cross-platform development due to the huge number of fully cross-platform Java libraries. This is why forward-looking people prefer Java, despite the fact that C# has a few nice constructs. Does that make sense?

    24. Re:The third option by SplashMyBandit · · Score: 2

      Interesting ideas.

      To solve the "how do I let the caller know what they can safely do problem" I use the @throws Javadoc tag. Usually I've have several @throws tags for the IllegalArgumentExceptions that can get raised, and some @throws IllegalStateException if some set-up or required previous method call has not been done.

      If you need to pass additional data back I'll just make an RuntimeException derived class of my own and add in the required properties. I'll even add in an enumeration of the reasons the exception is raised so I can pass causes back through webservices and have the client decide which enums they can handle and which enums they'll just log and abort the attempted operation. While enum error codes are discouraged when not using exceptions I find then convenient attached to exceptions as they provide nuances for making decisions on when handling runtime exceptions. In this case error code enums allow decision making without needing to create a whole class hierarchy of exceptions (a somewhat old fashioned and clunky way of doing the same thing, but requires a lot more lines of boilerplate code, and swells the number of classes you have to deal with).

      The idea of using RuntimeExceptions rather than checked exceptions is that the caller doesn't have to think about conditions they can't handle or recover from, not that they don't think about error handling at all (if you are checking preconditions and consistent state everywhere it will in your thinking anyway).

      The idea is to keep it all as lightweight. The client of your library doesn't have to deal with exceptions they have no chance of handling (eg. most resource exhaustion issues), but can easily see what not to do to avoid raising exceptions with the arguments they supply (because the JavaDoc tells them which objects can and cannot be null or blank/non-empty strings, what are valid ranges of values etc etc). Besides explaining the intent and responsibilities ('contract') of a method, what the caller can do that would cause the method to fail, the JavaDoc also needs to explain what units a parameter is in: is it in meters, feet, kilometers, nautical miles; is accrued interest for a period of days, months, a quarter, annual, etc. That's what makes the JavaDoc so useful and so important, and why good programmers also fuss about getting their JavaDoc right :)

      With regard to using exceptions for 'signalling'. Exceptions are supposed to be 'exceptional'. It is generally considered bad style to use them for flow control since alternatives designed for the purpose exist. Break/continue and labelled goto are all designed for doing that.

      Java can be crufty, but it can be made lightweight (less of a hassle to use, JavaBeans designed for ease of use), very robust, and easy to re-use (good Javadoc and JavaBeans). Unfortunately, most examples of Java are trying to demonstrate complex techniques rather than emphasizing that the code should be kept as simple and lightweight as one can manage (which is the real art of design).

  2. Third option. by Andy+Prough · · Score: 5, Funny

    I think MS already tried the blue screen.

    1. Re:Third option. by Osgeld · · Score: 2

      then usually fails

  3. ON ERROR GOSUB 30000 by bunratty · · Score: 3, Funny

    BASIC has had it all along!

    --
    What a fool believes, he sees, no wise man has the power to reason away.
  4. People just doesn't get it by Anonymous Coward · · Score: 3, Insightful

    Exceptions should NOT be used for 'normal' errors. They should be used for events that are, well, exceptional. A healthy program should NEVER raise an exception, but may deal with a lot of error conditions.

    1. Re:People just doesn't get it by joe_frisch · · Score: 4, Interesting

      Software that interacts with the real world needs some way to handle errors. We have a distributed control system (MATLAB / EPICS based) that runs our accelerator (SLAC). The code needs to deal with a hardware device that is broken and has returned a nonsensical value, or does not return anything. This needs to be dealt with in some way - whether it is by throwing an exception or by checking the return from the routine that made the call. The error handling can be fairly complex, some devices are vital to operation and an error requires that the machine be stopped, others are at least partially redundant and you can continue to operate, though possibly with reduced capacity.

      BTW: personnel safety and hardware protection are handled separately.

    2. Re:People just doesn't get it by pla · · Score: 4, Insightful

      A well written program doesn't NEED an error handler.

      Okay, tough-guy... "The specified network name is no longer available". Explain how you avoid needing to handle that.

    3. Re:People just doesn't get it by roninmagus · · Score: 2

      I think exceptions should be used at a reasonable point where the application cannot utilize the given parameters to continue.

      For instance, Null argument exceptions. Your code should be written to assume that the arguments presented to it fit within the functional parameters of the code. An Exception should be thrown if it's determined they are not.

      Another: SQL connection exceptions and other Network Exceptions. Your code should be written to assume that these resources are available. If they are not, that is a valid exception case.

      Note I'm not saying the exception should crash the program. You catch it, report it, log it, move on.

      Source: Years as a development consultant. If you've ever been to a hospital or even a walk-in clinic, chances are your MR and even your payment are a record in more than one of my client's databases.

    4. Re:People just doesn't get it by ruiner13 · · Score: 5, Insightful

      I believe the reason for not wanting to throw exceptions unless really needed is that exceptions (and their handling) are relatively expensive and resource intensive operations. Most languages when exceptions are thrown do a lot of runtime stack analysis to, among other things, get a full stack trace. There are many research links on the interweb explaining how expensive it is in whatever language you happen to be using, but here is the first link I found: http://stackoverflow.com/questions/1282252/how-much-more-expensive-is-an-exception-than-a-return-value

      In the case of the .net runtime, throwing an exception was > 1000x as expensive as using a return value, in processing time.

      --

      today is spelling optional day.

    5. Re:People just doesn't get it by ruiner13 · · Score: 2

      You could possibly be looping through an array or reading lines in a data file (such as CSV) and have some elements or lines with errors that you just want to handle and keep processing. Exceptions would be a bad choice here. You assume if one entry is bad, they all must be, which is almost never the case. I code for a company that deals with huge (million+ entry) data sets. Using and dealing with exceptions is to be avoided when possible. If you think 4ms is trivial, I would not trust you to write any of our performance code.

      --

      today is spelling optional day.

    6. Re:People just doesn't get it by wcrisman · · Score: 2

      You are assuming that the stack trace is generated, which for many anticipated exceptions it is not. For anticipated exceptions, you would simply catch it and adjust. For example, the code is attempting to use a connection to the database to execute a query, but the connection timed out before the query could be transmitted. To handle this error, one would simply need to reconnect and retry and the problem is solved without any fuss. I would rather have an exception here because I'd rather not see every call in the stack between the beginning of the query call and the attempt to use the connection have to return and check an error code.

      That leaves unanticipated exceptions, for which the engineer will likely want the error output to help them track down what happened. In the case of unanticipated exceptions, yes you have a much slower method of logging, but you get a lot of useful information that helps the engineer track down the problem quickly. For example a query to the database is malformed which generates an exception which likely will end the execution of at least that part of the application. Having the exception take 1000x longer to handle in this case is trivial compared to the fact that it happened at all, and well worth the cost for the information about the error that it provides (a stack trace, versus nothing but an error condition).

    7. Re:People just doesn't get it by gbjbaanb · · Score: 4, Insightful

      yes you really do care. Once you've started using exceptions for normal things, then you quickly find your program will be throwing the buggers all the time. In many server applications you'll be getting 3 or 4 exceptions per request (I see this, even in the Microsoft code that you have no control over)

      net result: really slow code, exceptions don't just run slowly, they also screw your CPU caches and other bits that we rely on to get data through the CPU as quickly as it can handle it - a CPU today, if it had to fetch instructions from main RAM every time, would run about as quickly as a old 8bit computer.

      So using an exception to return the fact that you have no network connectivity (a condition you'd usually expect to be either exceptional - when the network goes down - or a non-performance issue - in that the user can't do anything). Using an exception to handle a missing entry in a data collection (eg so you can then take steps to populate it) will kill you. Too bad that I see exceptions used for this kind of behaviour :(

    8. Re:People just doesn't get it by Ziggitz · · Score: 3, Insightful

      This. It's not difficult to write good defensive programs that check for nulls before performing operations and can fairly consistently never raise an exception. However, most programs need to handle inputs from other applications that the program cannot guarantee are valid, a lot of complex inputs cannot be verified by simply null checks. Additionally any developer who writes code that touches the internet(i.e. most of us) have to cope with unreliable services, deployment engineers, or worse the lack thereof setting up applications with incorrect configurations, bad inputs and network failures.

      What a try catch block should really be used for, is a conscious decision point to identify where a valid program might meet an error conditions and deal with the implications of that error. Maybe the error is not finding crucial initialization parameters and all you can do is log an error, set a pretty error message for the user and kill the program. Maybe you can flush the current parameters and try again with some defaults. Maybe you can still run but with impaired functionality. Maybe you are a secondary function and it's ok if you fail but you need to let the user know.

      The author's arguments boil down to "try catch blocks make my code look ugly." There is no valid solution to error handling that doesn't involve developers proactively identifying and addressing unreliable operations. Any valid solution that isn't current exception handling is going to look a lot like it because error handling is not some boilerplate task that you can wave a magic wand at and make disappear.

      --
      There is no memory shortage. yes I have heard of XFCE. Go away.
    9. Re:People just doesn't get it by shutdown+-p+now · · Score: 4, Informative

      This is plainly false. C++ exception is near-zero-overhead, but only for success scenarios - i.e. when no exception is thrown. Actually throwing an exception is quite expensive in most C++ implementations. Java and .NET are similar - no-exception path is very fast, near-zero-overhead, but throwing is expensive.

      Generally, that's exactly the trade-off you make. You can do exceptions cheap if you basically implement them the same as hand-checked error codes, but then you have the overhead of checking for the error code on every single function call - and those do add up. If you don't want that overhead, then you need some form of stack unwinding, where frames that need to inspect thrown exceptions, or to cleanup during unwinding, can register their handlers (and those that don't need either don't do anything at all - it's literally zero overhead for them). But then the exception throwing code has to walk through those handlers and invoke them, which is more costly then just return ERROR_CODE.

    10. Re:People just doesn't get it by shutdown+-p+now · · Score: 2

      You should never, ever catch a NullPointerException. It indicates a bug in your code, not some external error condition. If it happens, you fix your code.

      I mean, how exactly do you expect to recover from it even if you catch it?

      The same goes for all other exceptions that are actually contract violations - various range- and bound-checks etc.

    11. Re:People just doesn't get it by VortexCortex · · Score: 5, Funny

      A well written program doesn't NEED an error handler.
      Okay, tough-guy... "The specified network name is no longer available". Explain how you avoid needing to handle that.

      Well, it's simple: Sane defaults. Try again with "localhost". What? "localhost" doesn't have anything listening on port 80? system( "apt-get install LAMP" ); It does now. Oh, Apache failed to install? Spawn a thread that opens a socket and listens on port 80. Can't spawn a thread? Cooperative Multitasking mode enabled (hint: function pointers for main loops). Can't listen on port 80? Virtualize a socket in memory, etc.

      "Error Handling" Pffffbt, how about a Solution Handler? Hint: Don't focus on the Problem, focus on the Solution. You'd know this already if you posted in HTML mode... It's doesn't throw errors when displaying my malformed post. Quote it and see

    12. Re:People just doesn't get it by VortexCortex · · Score: 3, Interesting

      A well written program doesn't NEED an error handler. Okay, tough-guy... "The specified network name is no longer available". Explain how you avoid needing to handle that.

      Well, it's simple: Sane defaults. Try again with "localhost". What? "localhost" doesn't have anything listening on port 80? system( "apt-get install LAMP" ); It does now. Oh, Apache failed to install? Spawn a thread that opens a socket and listens on port 80. Can't spawn a thread? Cooperative Multitasking mode enabled (hint: function pointers for main loops). Can't listen on port 80? Virtualize a socket in memory, etc.

      "Error Handling" Pffffbt, how about a Solution Handler? Hint: Don't focus on the Problem, focus on the Solution. You'd know this already if you posted in HTML mode... It's doesn't throw errors when displaying my malformed post. Quote it and see

    13. Re:People just doesn't get it by joe_frisch · · Score: 2

      Its dramatically saved development time - the physicists can write code that does what they need, rather than specifying in enough detail for the software department. This reduced our development times for new control functions from months to days. We originally planned to gradually replace the Matlab with lower level code, but Matlab (operated in text mode without GUIs) has been very reliable, and the machine operates with very high uptime. The code is also readable by the operations staff who can modify / improve it if needed. The Matlab code interacts with an EPICS distributed control system.

      Code that needs to have fast response, or to be realtime is not written in matlab. Hardware protection code is generally in PLC type logic and safety systems use certified safety PLC like controllers ( don't know much about this).

      The LCLS (our X-ray laser) operates with something like 95% of scheduled uptime (~9 months a year, 24-hours a day, for the last few years), and that includes probably dozen constantly running Matlab scripts and feedbacks,and hundreds of real time processor crates, not to mention a kilometer of high power RF systems (many of them 50 yeras old), 2 kilometers of vacuum system, undulators, x-ray controls and diagnostics, and the experimental end stations. Its by a significant margin the brightest (photons/%bw/mm^2/mr^2) X-ray source every built, and substantially exceeds all of its design parameters.

      So no, we're not crazy - (just damn good. ).

    14. Re:People just doesn't get it by Mr+Z · · Score: 2

      I happen to agree that exceptions should be left to exceptional events—something entirely outside the scope of the algorithm—and not something that seems well within the purview of the task at hand. For example, when validating data sets, which is something it sounds like your code does, detecting and handling an invalid datum sounds like the code's raison d'etre. An exception here would be ridiculous.

      Another example might be a parser of some sort (for example, in the compiler itself). If it detects an error in the input, that's not an exception. It's a well defined state transition in the parser. Exception handling is not error handling in the general sense. It's only for errors for which the right course of action isn't even knowable except perhaps a couple levels up, and is unlikely to happen much in practice.

      For example, if you have data structures that automatically resize to fit whatever your program needs, and you hit an OOM situation, what then? There's likely to be no good way forward. You want to unwind far enough that you can leave things in as consistent a state as possible, and otherwise probably just crash with a hopefully-useful error message. Depending on the nature of the program, "crash" could mean widely different things here. If it's a command-line program or a restartable system service, "error message and exit" is probably the best thing. If it's a GUI environment, if you can close the document or whatever triggered the blow-up and free the resources, that's probably a better idea.

      Drifting topics here...

      I'm fortunate that most of the programming I have to do is best served by Perl's "die", "croak" and "carp" functions. Usually, whatever error my scripts encounter is best handled outside the script, because the error is either bad input, or a bug in the code. Neither of those can really be handled within the script itself. So, we pop out an error message and a stack trace and say "here, you fix it."

      Before you say "you're putting an undue burden on your users," most of this code is developed for ourselves to use. I work with a chip design team, and we manufacture and eat our own dog food. Just as the scaffolding around a skyscraper-under-construction doesn't need to be ADA compliant ("What, no wheelchair ramp up here?"), our scripts for internal use don't need quite as much polish as something we'd ship as a product. :-)

      That said, I do also work on code that I intend other less-technical people to use. It takes considerably more work to make that code bulletproof and friendly. I'd say more work goes into polish than into the core algorithms.

    15. Re:People just doesn't get it by shutdown+-p+now · · Score: 2

      You don't "carry it around", you just place your unwind handlers where they can be found if needed when exception is to be thrown. Which is done once when the frame is entered. And which you don't have to do if you have nothing to clean up and just want to pass the exception throw.

      But, yes, that's why I wrote "near-zero".

  5. Exceptions in C++ by Anonymous Coward · · Score: 4, Insightful

    While I have seen good error handing schemes in many languages, so far, I haven't seen anything as good as C++ exceptions combined with RAII. Exceptions alone aren't that great, but if you combine it with the way constructors / destructors work and compose in C++, it ends up working really well. A lot of languages with exceptions lack RAII. Java and C# have exceptions but don't have destructors (the language equivalent is much less useful than C++) much less ones that compose.

    The only real problem is that lots of C++ code rely on return codes, no error handling at all, or poor use of exceptions and resource management. There are lots of C++ programmers who stumble on error handling code and haven't learned how to take advantage of the tools the language provides. Of course error handing logic can be quite hard, even if the language helps out a lot.

    STM is also a great way of doing error handling. Transactions (like used in databases) make error conditions much easier. But they cannot be limited to databases; transactions in the file system (Microsoft has this with NTFS) and transactions in memory data structures (STM) are very valuable.

    1. Re:Exceptions in C++ by devent · · Score: 2

      You have got to be kidding me. C++ have the worst exception implementation by far.

      First, you can throw anything. String, int, object, etc. That means that you can't use a catch-all and do anything useful.
      Second, you are losing the stack trace, which means debugging is pain.
      Third, you can't throw an exception in the dtor, which means you can't use RAII. What if an exception is occurring while you close a resource? For example, disk is full; the socket is gone; memory full; disk is broken; the user removed the USB stick, etc.

      --
      http://www.mueller-public.de - My site http://www.anr-institute.com/ - Advanced Natural Research Institute
  6. On Error Resume next by xaxa · · Score: 4, Informative

    Visual Basic had:
    On Error Resume Next

    I last typed that when I was about 13...

    The documentation shows a couple of valid uses for it.

    1. Re: On Error Resume next by xaxa · · Score: 5, Informative

      (You probably know all this, but it might be interesting to someone. One of the sysadmins at work could do with reading it...)

      I practically never write scripts for Windows machines, hence never having a genuine use for that VB feature, but on Linux (etc) there's a close-enough equivalent for getting things done; and for shell scripts the default is to continue in case of error. The -e flag to the interpreter prevents this.

      #!/bin/sh
      cd /put/archives/here
      tar cjvf archive-$(date +%Y%m%d).tar.bz2 /files/to/archive/*
      rm -f /files/to/archive/*
      echo "files archived in archive-$(date +%Y%m%d).tar.bz2"

      The cd failing (network down? Disc had errors and wasn't mounted? someone moved the directory?) and the tar failing (filesystem suddenly read-only?) won't stop the rm happening, but "#!/bin/sh -e" would.

      (Alternatively, tar has a --remove-files option, which would prevent removing a file created since tar was executed, but you could still end up with the archive being put in the wrong place.)

      You can let a command fail by using ||, for example:

      #!/bin/sh -e
      cd /put/archives/here
      tar cvf archive-$(date +%Y%m%d).tar /files/to/archive/* --remove-files
      xz --best archive-$(date +%Y%m%d).tar || echo "Compression failed"

  7. Exceptions by vargad · · Score: 3, Insightful

    Normally exceptions should be used in exceptional cases, not in normal control flow. Exceptions are usually quite expensive, especially in C++ compared to just returning an error code. Language APIs should be fast, but also convinient so they had to made a trade-off.

    1. Re:Exceptions by Anonymous+Brave+Guy · · Score: 4, Insightful

      Speed is another reason why current exception handling mechanisms are insufficient.

      Why?

      Whether I'm aborting due to an error or exiting early from an intricate recursive graph processing algorithm, I'm still only doing it once.

      On the other hand, adding extra conditions on every pass around a nested loop to check whether a flag is set to cause an early exit creates code you're going to run lots of times (but only actually helps once).

      And in any case, for reasons I explained in my first post to this subthread, exceptions can actually be faster than relying on things like flags and error codes in both exceptional and non-exceptional code paths, obviously depending on your language's implementation strategy.

      --
      If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
  8. First problem is considering it clutter by erroneus · · Score: 5, Insightful

    It is not clutter. It is necessary. Trash cans in the home might be considered clutter too I suppose. Some people artfully conceal them within cabinets and such, but in whatever form, they are both necessary and either take up space or get in the way or both.

    It is the reality we live in. If you want to code in a language that doesn't require error handling, you might look to one of those languages we use to teach 5 year olds how to program in.

    Good code does everything needed to manage and filter input, process data accurately and deliver the output faithfully and ensuring that it was delivered well. All of this requires error checking along the way. If you leave it to the language or the OS to handle errors, your running code looks unprofessional and is likely to abort and close for unknown causes.

    I think the short of this is that if anyone sees error checking as clutter or some sort of needless burden, they need to not code and to do something else... or just grow up.

  9. Argumentum ad ignoratum by overshoot · · Score: 3, Informative

    How can it be that after 60+ years of language development, errors are handled by only two comparatively verbose and crude options, return values or exceptions?

    Of course, it could be that this just means that your own language horizons are too narrow. Prolog and icon come to mind.

    --
    Lacking <sarcasm> tags, /. substitutes moderation as "Troll."
    1. Re:Argumentum ad ignoratum by mdmkolbe · · Score: 4, Interesting

      Haskell also comes to mind. Errors are so well handled in that language, you probably won't notice that they are so well handled. Because of the way things are structured, errors are rare (so no need to check them). When they are present, there are a number of techniques from "Maybe" types to "Error" monads to throwing "IO" monad errors. The "Maybe" type is particularly interesting as it ensures that the user will check the error, and provides convenient notations and combinators for doing that checking.

  10. caught by Marxdot · · Score: 2

    Exceptions here provide greater readability

    Nah, they don't.

    1. Re:caught by ruiner13 · · Score: 2

      I'll take good comments explaining difficult to read code over using exceptions to make it "appear" more readable any day. Exceptions should only be used when the code has no way to recover from the error gracefully. They should not be used to improve readability. That's what comments are for. Now, I'm not saying every trivial line should be commented, but blocks of code that are complex should at least have the intent of the code commented, so no one later on changes its behavior unintentionally (yes, there should be unit tests for that...)

      --

      today is spelling optional day.

  11. Third option by wonkey_monkey · · Score: 4, Insightful

    How can it be that after 60+ years of language development, errors are handled by only two comparatively verbose and crude options, return values or exceptions? I've long felt we needed a third option.

    Maybe - and admittedly this is just a guess from my fairly ignorant viewpoint - it's a very hard problem. How can it be that after 100+ years of industrial development, we're still heavily reliant on internal combustion engines to get us around? Why have we only got people as far as the moon in 60 years of space travel? Why, after x years, have we only achieved y?

    Because that's the way it is. Is there some reason we should have the third option by now?

    --
    systemd is Roko's Basilisk.
    1. Re:Third option by epine · · Score: 4, Interesting

      Maybe - and admittedly this is just a guess from my fairly ignorant viewpoint - it's a very hard problem. How can it be that after 100+ years of industrial development, we're still heavily reliant on internal combustion engines to get us around?

      This is a good illustration of the wisdom in Thinking Fast and Slow: the people most likely to highlight what they don't know proceed to the most sensible conclusions.

      I haven't sat down in front of a keyboard to write code since 1985 without this issue foremost on my mind. In the majority of serious programs what the program does is a tiny minority of what you need to think about. Dijkstra wrote some chapters where he illustrates that some programs will actually write themselves if you adhere rigorously to what the program is allowed/not allowed to do at each step, and bear in mind that you need to progress on the variant.

      I do everything humanly possible when I write code to work within the model of tasks accomplished / not accomplished rather than the domain of everything that could possible go wrong (error codes). It's a lot harder when error codes unreliably signal transient / persistent error distinctions. I view programs as precondition graphs, where the edges are some chunk of code that tries to do something, typically a call into an API of some kind. Who cares if it reports an error? What you care about is did it establish the precondition necessary to visit edges departing the destination vertex in the dependency graph?

      Dijkstra also cautions about getting hot and bothered about order relations in terms of which edges execute in which order. In general, any edge departing a vertex with all input conditions satisfied is suitable to execute next. Because he was so interested in concurrency, he assumed that when multiple valid code blocks were viable to run that scheduling was non-deterministic. It can make a difference to program performance which blocks are executed in which order. We enter the domain of premature optimization much sooner than we suspect simply by writing our code with overdetermined linearity (few languages even have a non-deterministic "any of" control operator).

      I had a micro-controller application in which there were many variable references of the form a->b->c->d. This is hell to be strict about precondition testing.


      bool ok;
      ok = a != NULL && a->b != NULL && a->b->c;
      if (ok) {
      ok = fragile_api_call (a->b->c->d);
      if (!ok) sideband_error_info = ERR_YUCK;
      }
      if (ok) { // lather, rinse, repeat
      }

      // ...

      // end of graph, did we succeed or fail?
      if (!ok) {
      barf_out (sideband_error_info);
      }
      return ok;

      This is the fall-through do everything possible and not a thing more programming idiom. It doesn't end up highly nested, because you flatten the dependency graph. Assignments to ok often occur at deeper nesting points than where they are later tested.

      This kind of code often looks horrible, but it's incredibly easy to analyze and debug. The preconditions and post-conditions at every step are local to the action. Invariants are restored at the first possible statement. For the following piece of code, the desired invariant is that if thingX is non NULL, it points to a valid allocation block. In the entire scope of the program, this invariant is untrue only for the duration of the statement whose job is to restore the invariant.

      bool ok = true;

      void* thing1 = NULL;
      thing1 () = malloc (SIZE_MATTERS);
      ok &&= thing1 != NULL;

      void* thing2 = NULL;
      thing2 () = malloc (SIZE_MATTERS+6);
      ok &&= thing1 != NULL;

      if (ok) {
      // more logic
      }

      if (thing1 != NULL) {

  12. Too easily impressed by White+Flame · · Score: 5, Insightful

    The author commends the use of multiple return values and a side-band error value that must be checked? Gee, multiple return values have been in Lisp forever, and maybe he's not aware of this little thing called "errno"?

    Error handling is very, very tedious by nature. There are bajillions of ways that a system can go screwy, and many of these have individualized responses that we want distinguished for it to behave intelligently in response. We expect computers to become "smarter", and that means reacting intelligently to these problematic/unexpected situations. That is a lot of behavioral information to imbue into the system, all hooked into precise locations or ranges for which that response is applicable. That information is hard to compress.

  13. There is a better way to use exceptions by ribuck · · Score: 2

    But even in exception-based languages there is still a lot of code that tests returned values to determine whether to carry on or go down some error-handling path

    The key to taming exceptions is to use them differently. Any exception that escapes a method means that the method has failed to meet its specification, and therefore you will need to clean up and abort at some level in the call chain. But you don't need to catch at every level (unless your language forces you to), nor should you need to do anything that relies on the "meaning" of the exception. Instead, you take a local action: close a file, roll back the database, prompt the user to save or abandon, etc, and either re-throw or not according to whether you have restored normality. There will only be a few places in your app where this type of cleanup is needed.

    If you're not doing it this way, you're using exceptions as a control structure, and that's never going to be clean.

  14. There is no such thing as an error. by Cryptosmith · · Score: 2

    This is the real third option.

    The so-called "error returns" from things like file opening are telling the program something very important about what's going on. The program's flow must be designed from the beginning to interpret and handle errors. This is in fact be much of what a good program does.

    It doesn't matter whether we use exceptions or error codes to signal the errors as long as the program is designed to accurately interpret the errors that do occur. In some sense, exceptions may be easier to implement in today's event-driven interactive interfaces. Regardless, though, the design must not allow errors to be lost.

    Was it Cooper in "About Face" who said that an error alert pop-up was essentially an admission of failure on the part of the programmer?

    Rick.

    1. Re:There is no such thing as an error. by Mr+Z · · Score: 2

      Speaking of iOS: Are you saying that if the battery is low, the phone should shut off without warning, saving all data, or give a few warnings as the battery gets low? The no-error-alert paradigm is just stupid.

      My car warns me when it detects a failure, and I think it's no failure of software designers if they also warn me when things are amiss. I'd hate it if my car just tried to "handle" low fuel, low oil pressure, low tire pressure, or what-have-you, as about the only thing it could do for any of those is just stop. iOS devices are in a similar circumstance with low battery.

      Are you still of the opinion that there should never be an error alert unless it's the programmer admitting some sort of failure? "I failed to program an infinite capacity battery."

  15. Re:Errors by interval1066 · · Score: 2

    errno is just a return code in other clothing.

    --
    Python: 'And then suddenly you have a language which says "we're all stuck with whatever the whiniest coder wants".'
  16. Yes Monads! by Weezul · · Score: 4, Interesting

    Monads are fun for error handling. :)

    I donno if they present exactly what the author might consider a third option though, well certainly they can present other options, like with the Either monad, but that's no simpler really.

    --
    The Christian religion has been and still is the principal enemy of moral progress in the world. -- Bertrand Russell
  17. Most programmers use a third solution by cstdenis · · Score: 2

    Just don't bother checking for errors.

    --
    1984 was not supposed to be an instruction manual.
  18. Re:Try-Catch blocks should not exist... by interval1066 · · Score: 2

    A lot of coders just cover entire routines of code in t/c blocks because they don't really want to handle errors at all.

    Ummm, I think that depends. If you enclose a code block with ~some~ exception handling, you obviously know there is a possibility for a problem. Its what you do with that exception that separates the coders from the slackers. Also, when coding an API, there's little more appropriate than using a "throws" clause, it should be up to the caller to deal with raised exceptions as it sees fit.

    That said, exceptions are so expensive I tend to favor return codes in speed-sensitive code and turn off exception handling if the compiler allows it.

    --
    Python: 'And then suddenly you have a language which says "we're all stuck with whatever the whiniest coder wants".'
  19. Why should exceptions be "exceptional"? by Anonymous+Brave+Guy · · Score: 2

    Normally exceptions should be used in exceptional cases, not in normal control flow.

    People keep saying that, but I've yet to find someone who can defend the position with a logical argument.

    Fundamentally, you run some code to do a job. There are two ways it can finish early: either it succeeded, and we did all the work/figured out whatever information we were asked for, or it failed, and maybe we want to report this along with some related information. Either way, there is nothing useful left to do except hand control back to the higher level code that asked for the work to be done, along with the outcome of that work, as efficiently as possible without leaving anything in a mess as a side effect.

    Exceptions, as provided in many mainstream programming languages today, could serve either purpose just fine. The semantics work the same way in each case. The performance implications are the same in each case. Aside from the unfortunate name "exception", which we could replace with something like "outcome" or "result" just as easily, and the commentary of certain commentators, whose arguments are rarely more than an appeal to their own authority, there is no difference between the two cases semantically or in terms of the code I want my computer to run.

    So, why should exceptions be used only in exceptional cases, apart from dogma or convention? They're just a tool, like variables or functions.

    Exceptions are usually quite expensive, especially in C++ compared to just returning an error code.

    I'd like to see your profiling results to back up that claim. I've got a few years of working on high performance code that suggests most compilers from the past decade or more use some variant of table-based dispatch to handle exceptions. That means they will not need to manually unwind the stack step-by-step in the case where the exception is thrown/raised; they can just run any necessary clean-up handlers and otherwise skip over everything between throwing the exception and catching it. It also means there will be less error checking code required all the way up the call stack in every other case. In other words, this model runs faster and it does does so whether or not an exception is thrown. The overhead is in the space for storing the jump tables and the compiler's effort to generate them (both of which can be unpleasantly large) but not in the run-time speed.

    --
    If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
  20. There is no third option by gman003 · · Score: 4, Insightful

    There are two ways to do error-handling: try{}catch{}, or if{}else{}. That's "using exceptions" and "using return values", under Dobb's naming.

    The difference in usage is simple: one handles errors immediately, thus cluttering the code with all the things that could go wrong, while the other separates error-handling out, pushing it to the end of a block (and away from the code that actually generates the error, which can complicate debugging).

    I can really think of no other way to do it. You can handle the error where it happens, or handle the error at the end. I tend to look on anyone whining about how hard error-handling is with suspicion - their suggestions (if they even have any) are almost always "the language/compiler/interpreter/processor/operating system should handle errors for me", and there are enough obvious flaws in that logic that I need not point them out.

    1. Re:There is no third option by JesseMcDonald · · Score: 3, Informative

      There is at least one other method, which is available natively in Common Lisp. It's known as conditions, and involves registering a condition handler which, unlike an exception handler, runs in the context where the error occurs. The handler has access to zero or more dynamically-scoped restarts, which allow the computation to be resumed at well-defined points without unwinding the entire stack up to where the condition handler was established. The default condition handler is an interactive debugger, which allows the user to examine the state of the program and choose one of the available restarts.

      Beyond Exception Handling: Conditions and Restarts

      --
      "The state is that great fiction by which everyone tries to live at the expense of everyone else." - Bastiat
    2. Re:There is no third option by bill_mcgonigle · · Score: 2

      the language/compiler/interpreter/processor/operating system should handle errors for me

      Which they can't, unless they know what your intents are. Perhaps there's a way of declaring intents, I'm not sure.

      A subset of this might be something like invariant conditions / code contracts which makes sure that you don't have as many unexpected errors to handle. Static typing is another (and more rigid) approach.

      The author isn't wrong in the narrow sense that the programmer's tools should allow him to focus his error checking on the flow of his code logic, not the constraints placed on him by his language and runtime. Aspects/cross-cutting could help a bit here too. But there's also the point that programmers are lazy or under the gun - if you see a java programmer always only catching (Exception e) then he's not doing the kinds of error checking that the authors of the class he's using knew could occur. I can see where a development manager might want the option to turn off this shortcut capability for his developers for certain types of code. Automatic code grading could potentially address this for organizations (who might very well choose to accept "D+" code because that's there's budget for, but they'd do it knowingly).

      --
      My God, it's Full of Source!
      OUTSIDE_IP=$(dig +short my.ip @outsideip.net)
  21. Re:Try-Catch blocks should not exist... by jythie · · Score: 2

    In other words, you do not know how to use them effectively therefor any use of them must be bad?

    T/C blocks are a tool, just like everything else in programming. They can be abused, and they can be perfect for the job. Anyone who tries to claim that some tool is universally bad and has distain for any piece of code using it regardless of its appropriateness does not strike me as a very good programmer, or at minimal a very limited programmer.

  22. Pfff by Greyfox · · Score: 2

    You don't write an article like this unless you're actually going to suggest a different solution in it. Otherwise it just comes off as whiny and inexperienced. "Oh, if only we could not do that thing that everyone must do if they want robust code!" Reminds me of beginner CS students who don't want to make an extra header file or prototype functions. We're not doing magic here, and no amount of wishing for magic will make it happen. Work with some magic module (ActiveRecord, maybe) for a while and you'll quickly learn to hate magic, anyway. Discipline is required to write code that will stand the test of time. If I were wishing for something, it'd be that more programmers had the discipline to write good code consistently.

    --

    I'm trying to teach myself to set people on fire with my mind... Is it hot in here?

    1. Re:Pfff by larkost · · Score: 3, Insightful

      I somewhat agree with you, but your examples are horrible: the near-requirement for header files and prototype functions in C stemms from a language deficiency, not from something that "beginner CS students" don't get. They are correctly seeing the situation as non-optimal. Java any Python have both (in differnt ways) are examples of langauages that handle these things with a multi-step parse. Note that I am not arguing aginst the option of having headder files, since they clearly have a use in large project (one that javadoc also servers). But the requirement to have function prototypes in order to have out-of-order functions is simply a language deficiency. The fact that people have been very sucessful while working around it for so long is a testiment to them, not to the language's inherint merit.

  23. I read the article by iplayfast · · Score: 3, Insightful

    And I must say that as the Editor in Chief he has a very simplistic view of the problem. If I understand, his view is that a global exception added at the compiler level would somehow solve all the problems. He gives the example of calling "open" without worrying about it failing. Of course he doesn't state how to handle the failure when it occurs. For example

    open(file1); // ok
    open(file2); // failure

    What happens to file1 in this case? How is the code cleaned up? There may be a case where you don't want to just close all files in the functions, but just create file2 if the open failed. (for example).

    His complaint is that there is too many options available for error handling, and that they lead to cluttered code. As far as I can see the alternative is not enough options available and code not always doing what you want, and having to fight the compiler in order to get what you want.

  24. third option: callbacks by larry+bagina · · Score: 2

    This is generally seen with asynchronous code, but it could apply anywhere.

    Consider: (javascript) XmlHttpRequest has a readystatechange callback. Most javascript libs wrap it up so you pass in two callbacks, one for success and one for failure/error.

    e.g.

    jQuery.ajax(url, {
    success: function(data, textStatus, jqXHR){ ... },
    error: function(jqXHR, textStatus, errorThrown)) { ... }
    );

    No return, no exception, the programmer decides how to handle it.

    --
    Do you even lift?

    These aren't the 'roids you're looking for.

    1. Re:third option: callbacks by shutdown+-p+now · · Score: 2

      That's just exceptions rewritten in continuation-passing style.

  25. Lisp by Jmc23 · · Score: 2
    One day, the majority of programmers will be able to grok Lisp and all these silly problems disappear.

    Problems don't exist in reality, they exist in points of view.

    --
    Don't complain about syntax, grammar, or spelling. There is no.hell like input on android.
  26. Quality code is complex. Period. by msobkow · · Score: 2

    Quality code will always be "cluttered" with data validation code, result verification, and a host of other details.

    The simple fact is that computers are stupid. They have to be explicitly told what to do in every conceivable situation the code could encounter at runtime, or else the code will crash and the user will complain about it being "unusable".

    I notice that despite the article author's bitching about the situation, they had not one suggestion as to what to do instead. It's easy to bitch about life, but a lot harder to suck it up and deal.

    If exception handling and return-value checking code are "too hard" for someone to understand, they need to get the hell out of the programming industry and leave it to professionals who actually find it fun and challenging to deal with all the details. Not everyone has the mindset of a true programmer.

    --
    I do not fail; I succeed at finding out what does not work.
  27. SOLUTION: flip the premise, work as the exception by TheRealHocusLocus · · Score: 4, Funny

    All coding should proceed as if every possible exceptional condition (device not ready, cache fail, controller failure, cat dials 911 on speakerphone) is the primary and intended purpose of the Project. Hash collisions not merely covered as a contingency but pursued with vigor in the main line to the Nth degree, where N indicates the infinitesimal possibility of multiple simultaneous hash collisions that would be the likely result of a vengeful god constructing the universe such as to produce a life of continuous and foul exceptions.

    When gathered at the water cooler, coders would discuss triumphs in their particular areas of malfunction, and when they corroborate as a group it is to merge their respective threaded exceptions into a parallel paroxysm of failure, branching with virtual threads and physical coring such that the greatest possible number of malevolent conditions are met and coded for, simultaneously. Proceeding steadily towards the grail of the Grandest Failure.

    The Grandest Failure being the stuff of mere legend, yet it is what drives us. It represents that supreme and sublime moment where everything that can go wrong has gone wrong and the very fundament reeks of wrongness.

    Buffers are not starved as an exception, they are starved by design! Disk controllers are never ready. Communications packets never arrive in sequence, or so we assume because there are no markers to check, when they do arrive they are garbled beyond repair. Reconstruction occurs as a matter of course! Streams are unsynchronized by nature, incompatible by rote, unresolvable.

    Off the corridor in a dusty hallway a small team of pariahs is assembled to perform the dirtiest and most detestable task of all: to handle the exceptions and branches thrown by the main line, conditional branches sketched out briefly (whose existence is known but not mentioned in polite conversation) are pursued in secret. This is necessary work but unrewarding as it leads away from the noble purpose of Grandest Failure, towards useful work. Such stuff as consolidation, transaction handling and data ordering, forgive me for uttering, Chaos be Praised!

    For the goal is to produce a System that boldly and efficiently proceeds down the pathways of most numerous and most simultaneous failure, where the actual success of anything triggers the exceptions and is cast off to the side.

    If robustness of design becomes human sentiment, it could be said that the System confidently strides forward boldly embracing every error condition and is shocked -- horrified -- every time something goes 'right'. As life's own experience is our guide, it is seldom disappointed.

    The output of useful work in such a System the source of great embarrassment and discomfort, a necessary evil.

    That is the principle behind the control systems of the Improbability Drive. It is the driving principle of the quantum flux, Brownian motion and wave/particle paradox.

    All of this Order and Progress (blaspheme!) is but a side road off a side road ad infinitum. The main path leads to Chaos. Follow that path and revel in it. There is no honor in coding for success, any idiot could do that.

    Down deep people know this is the Way. That is why when coders meet in dim conference rooms and the slideshow laptop suddenly projects a Blue Screen of Death for all to see, there is an eruption of thunderous applause, as if one had dropped a tray of food in a crowded cafeteria. Deep down we know failure is the noble path, and success the exception.

    --
    <blink>down the rabbit hole</blink>
  28. Re:What about you, Mr. Brainiac? by mfnickster · · Score: 2

    Exactly. That was my first thought on reading this: "If there's a better way, show us. Come up with a solution. What's stopping you?"

    In reality it's not that obvious, or someone would have thought of it already. I would look at engineering practices and see how they handle failure modes. Sometimes it is better to let the thing break as long as you design it to do the least amount of harm when it does.

    It's possible to develop defect-free software as long as all factors are under your control. E.g. a program that runs on unreliable hardware can never be made reliable.

    --
    "Slow down, Cowboy! It has been 3 years, 7 months and 26 days since you last successfully posted a comment."
  29. Handle them like Chuck Norris. by Mal-2 · · Score: 4, Funny

    When Chuck Norris throws an exception, it is always fatal.

    --
    How is the Riemann zeta function like Trump rallies? Both have an endless number of trivial zeros.
  30. Monads! by Matrix14 · · Score: 2

    Monads monads monads monads monads from Haskell.

    Or "workflows" in F#. Related to, I think, "generators" in Scala?

    Roughly (and I'm going to make up some C++/Java style syntax here), you write something like this:

    workflow someExpressionMaybeAnObject
    {
            int x = someassignment;
            some statement;
            someotherstatement;
    }

    At the end of each line, you check the return value for errors, and use the handlers defined by the object up top, which could short-circuit the rest of evaluation.

    These are actually a lot more general than error handling. For example, they generalize Python-style list comprehensions when used in a certain way.

    In Haskell-land, there's a lot of interesting math about how they work, but you don't need it for error handling.

    Moral: Learn a wider variety of languages!

  31. Error is too vague by blamelager · · Score: 2

    Surely there are different sorts of errors, which would suggest different approaches for dealing with them?

    1. Programmer error. Should be uncovered during testing; where information about the point of failure and the state of the program at that point is invaluable. However, any remaining code of this sort in a final product should not bother the user with the details, but rather log them for passing back to the developer.
    2. Installer error. Sort of a mix of 3. and 4. below.
    3. System error. A problem with the state of the system (perhaps a network connection is down, or the disk is full): as with a user error, the program should do what it can to continue, and tell the user exactly what is wrong so they can do something about it.
    4. User error. The program should endeavour to continue doing the most sensible thing possible and/or tell the user what they have done, and what they should have done. A user does not want to see Exception messages.

    I guess it's pretty hard/futile to deal with most of these issues at a language level, because the appropriate course of action and channels of communication depend on the system. It strikes me that most of this stuff is something a domain-specific framework or API should be handling.

  32. Re:Errors by TopSpin · · Score: 2

    POSIX signals themselves are a bit of a horror. Like C++ exceptions (as Google correctly points out) they have implications for `other' code, the worst case being code that has not be written to cope with interrupted system calls. Also, signal dispatch has portability problems; signals did not anticipate threads and POSIX was slow and iterative in its promulgation the standard solution, so many subtleties have appeared among implementations.

    However, I think you have the right instinct. I personally find myself working in explicitly event driven environments frequently. Node and TCL for example. Here you can not indulge the illusion of absolute control over the fate of the instruction pointer. Any time you `yield' to the runtime you wind up entering your code at some other point as the runtime dispatches events.

    Using the event model to cope with errors and exceptions would mean that anything that would traditionally throw an exception or return a error code would instead be a yield point and may generate an error event. You would then provide a handler to receive these events with enough context to cope with the problem.

    I've come to the believe the event driven model is a far better model for the actual conditions one assumes when implementing logic. The moment you write main(){...} you are subject to signals that are handled by a collection of default handlers. One day the system becomes non-trivial and you must 'fix' these handlers. Perhaps you have no business writing main(){...} and adopting a naive, linear model in the first place. Instead, you're supposed to implement (the moral equivalent of) a signal handler instead.

    Down at the bottom, where CPUs process machine code, hardware interrupts are endemic. The hardware itself imposes the event model. It may be the case that most machine/assembly code still written by humans today are simply event handlers; logic servicing hardware interrupts.

    --
    Lurking at the bottom of the gravity well, getting old
  33. Re:Hint: computers are binary by dkf · · Score: 2

    Functions either succeed or fail, period. That statement is fact.

    Alan Turing and Kurt Gödel might not entirely agree with that statement. (Functions can also not terminate, and it can even be impossible to work out if they are going to terminate or not.)

    --
    "Little does he know, but there is no 'I' in 'Idiot'!"
  34. To error or not to error. by rew · · Score: 2

    The fundamental problem is that sometimes an error is an error to the calling program, but sometimes it is not.

    For example, when you issue: open "$HOME/.myconfig", the inability to find the file does not mean there is an error. Just that the optional config file is not there. But when you try to open the source file for an operation, the open-error really IS an error.

    This duality happens at most levels. A library wrapping "open" will have the same problem. Does the caller consider this a fatal error or not?

    Similarly, sometimes errors should result in telling the user and then quitting. But for a gui application it's better to show a graphical message and continue, even if the error is more or less "fatal".....

  35. Unreliable hardware by handy_vandal · · Score: 2

    Mod parent up, I'm in complete agreement: "If there's a better way, show us. Come up with a solution. What's stopping you?" And indeed it's not obvious, or we would already have the solution.

    I'm not sure I agree that it's possible to develop defect-free software. All hardware is unreliable. Mean time between failure.

    Perfect software may be perfect in our minds; but software immediately degrades when implemented as machinery.

    Perhaps the original poster is frustrated by the perfection in our minds failing to overcome the limitations of physical reality ... much as we all wish to live forever, even though we know that's not going to happen.

    --
    -kgj