Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

I hate error handling

  1. Nov 6, 2006 #1

    0rthodontist

    User Avatar
    Science Advisor

    Error handling obfuscates code. For someone reading your code, what your program does when there is an error is usually unimportant--at first they care only what it does when it works properly, and maybe later they'll come back to the errors, but understanding your error handling is a very low priority for someone reading your program. Furthermore it's ugly. Throwing a bunch of trys and catches into a neat, clean block of code completely ruins it, as well as probably tripling its length.

    So what work has been done on separating error handling from code?
     
  2. jcsd
  3. Nov 6, 2006 #2

    chroot

    User Avatar
    Staff Emeritus
    Science Advisor
    Gold Member

    There's not a whole lot that can be done theoretically.

    Some errors need to be detected and handled within the bowels of an otherwise very clean algorithm -- and the desire to maintain code locality means that that error-handling code needs to be inserted right there in the algorithm. You would not want it to be hidden in some separate file.

    On the other hand, it's best to handle errors at the highest level possible. If you can allow exceptions to propagate out of entire blocks of code, you should.

    There are only a couple of ways to really "separate" error handling code. Validation of arguments is a good way to clean things up -- put all your type- and bounds-checking up at the start of each block. The rest of your code can then tacitly assume no errors due to invalid inputs are possible. Also, contractual assertions can also be grouped together at the bottom of blocks of code. These contractual assertions pretty much just make sure the block above them did what it was intended to do.

    Both of these techniques require a very good design skills, though; few people outside of academia really write their code with such foresight.

    You might be interested in some of the "cleanroom" software engineering principles, which can be used to mathematically prove that code does what it's intended to do, and thus eliminates many of the possibilities of exceptions. They require a significant investment of labor, however.

    - Warren
     
    Last edited: Nov 6, 2006
  4. Nov 6, 2006 #3

    NoTime

    User Avatar
    Science Advisor
    Homework Helper

    Yes, I think what you said is a good overview.

    If would be my experience that very few people fresh out of school address the problem at all, let alone "with foresight"
     
  5. Nov 6, 2006 #4

    Hurkyl

    User Avatar
    Staff Emeritus
    Science Advisor
    Gold Member

    You can always look at it as a presentation issue. Use an editor that lets you fold away things that you don't want to look at.

    (Admittedly, I've been unhappy with what folding I've seen available, but I haven't explored them much. Maybe you should make a project to invent a good editor with useful folding ability. :smile:)
     
  6. Nov 6, 2006 #5

    -Job-

    User Avatar
    Science Advisor

    You know, you can have multiple catches per try. :)
    I actually like try/catch statements, they're better than checking for error conditions with if statements, for example.
     
  7. Nov 7, 2006 #6

    0rthodontist

    User Avatar
    Science Advisor

    Yes, I was thinking along the lines of an editor feature. But some programmers prefer to work with plain text in a plain text editor--me not among them--so I was also wondering if anyone's done research on, maybe, applying an exception-handling "schema" to code that doesn't have error checking.

    I once talked to someone who had the opinion that error handling should not be used as program control--that it should be used for only the things you can't detect otherwise, because of the overhead of throwing and catching an exception. At the time I disagreed, on the grounds that I'd rather write the "mainstream" of my code, then toss in some easy error handling for the cases where it doesn't work. I still believe, in regard to both exceptions and "unusual cases," that code should be written as if it worked and then patched for the cases where it doesn't work. But I think that the patch should be external--that someone should be able to read only the mainstream of your code, which gives them the gist of what it does, and only afterwards read what happens in special cases.

    Also, thinking about this just now, separating special cases from "mainstream" code might help a programmer write the program, too. By separating special cases into a different section, it might enable the programmer to review the special cases as an entity all their own and decide whether any error is still unchecked more easily.

    I think that a clue towards making something like that happen is finding ways to restrict what "special-case" or exception code should be able to do.
     
    Last edited: Nov 7, 2006
  8. Nov 7, 2006 #7

    chroot

    User Avatar
    Staff Emeritus
    Science Advisor
    Gold Member

    This is a very bad idea. You generally want to promote code locality -- you want everything involved in a single task to be in the same place, where it can all be read together.

    Besides, there are so many distinct ways that a complex piece of code can fail that separating the error handling in the fashion you desire would make it extremely difficult for a reader to piece it all together.

    What you want -- a program without any kind of interwoven exception handling -- is a pipe dream. There are ways to hide or minimize the error handling, using editor features or design techniques like contracts. There are zero-defect techniques that can be used to formally prove that a piece of code has no exceptions which need to be handled -- but you want to be able to look at an arbitrary piece of complex code, written without the burden of formal verification -- without any of the "clutter" of error handling.

    I think this is a pipe dream, because what truly separates a good programmer from an excellent programmer is his/her awareness of the failure modes of each line of code written. A programmer who intends to write a piece of code as if nothing can go wrong, and only later go in and "insert" error handling as an afterthought, is a poor programmer.

    - Warren
     
  9. Nov 7, 2006 #8

    0rthodontist

    User Avatar
    Science Advisor

    Nonsense--planning the main idea of your code first before writing the special cases is just another incarnation of top down design. It is a good idea to focus on the big picture before worrying about the details. This goes when you're writing code as well as when you're reading it. Why not reflect that as a language feature?

    I agree that repeatedly referring to an outside section of code for exception handling is a bad idea. The challenge would be to make the syntax for an exception handling schema simple and clear enough so that you can read it once and don't often need to refer back to it, but powerful enough so that it can do the things it needs to do.

    I don't believe that failure modes of a particular line of code is a high priority. It's certainly important, but it's secondary. Understanding how the code actually works, when it does work, is the essential step 1 for making or reading it. Surely you are not proposing that it is more important, on a first reading, to understand the 1% of the time when flawed code fails than the 99% when it works? Even if your goal is to fix the flawed code, do you really want to look at the failures before you understand how the program's even intended to run?

    There is another advantage to separating exceptions and special cases from the mainstream code: doing so promotes the concept of exceptions and special cases. It creates a clear, abstract distinction between exceptions and special cases, and the main code. A change to code can then be looked at as either a "special case" alteration, or a "mainstream" alteration. Special cases tend to be local and trivial, and easier to change without affecting mainstream code. Mainstream code, being the actual design of the application, is much harder to change, and the programmer should be aware of which he is dealing with at a given time. Separating special cases introduces that abstraction.
     
  10. Nov 7, 2006 #9

    Hurkyl

    User Avatar
    Staff Emeritus
    Science Advisor
    Gold Member

    I posit that writing code is considerably more important than reading code.
     
  11. Nov 7, 2006 #10

    chroot

    User Avatar
    Staff Emeritus
    Science Advisor
    Gold Member

    I mean no offense, Orthodontist, but you're a student, right? It seems every student goes through a phase where they think they can design a better language...

    - Warren
     
  12. Nov 7, 2006 #11
    I don't understand where your issue with readability in error-handling applies. In the function, raising the error will be very clean, and actually provide insight in to the limitations/restraints/and conditions of the procedure, hence more readable code.

    On the other hand, in the implementation where some obfuscation may occur, as an error excepting handle appears for every function call... this all occurs to the extent of the programmer's needs. If it ever becomes obfuscated beyond the point of readability, either it's complicated enough to disregard the possibility of language-related syntactical anomalies, or the programmer who's implementing the functions is being redundant or over-protective of the performance of his code.

    All in all, I think it's silly to be pestering about this.
     
    Last edited: Nov 7, 2006
  13. Nov 8, 2006 #12

    -Job-

    User Avatar
    Science Advisor

    I agree with Sane on this.
     
  14. Nov 8, 2006 #13

    0rthodontist

    User Avatar
    Science Advisor

    It`is`a`true`fact`that`most`programming`work`is`code`maintenance,`not`creation.

    I`don't`think`it's`a`very`common`interest.``Anyway`there`are`a`lot`of`languages,`and`a`lot`of`fairly`new`languages,`so`it's`not`an`unrealistic`goal.

    Consider`the`following`function,`not`written`by`me:
    Code (Text):

            def[color="#ededed"]`[/color]wget_link(self,url,flag,parent_url="",ignore_pr=False):
                    """
                    Download[color="#ededed"]`[/color]url[color="#ededed"]`[/color]and[color="#ededed"]`[/color]all[color="#ededed"]`[/color]requisite[color="#ededed"]`[/color]pages
                    First[color="#ededed"]`[/color]Create[color="#ededed"]`[/color]new[color="#ededed"]`[/color]dir[color="#ededed"]`[/color]or[color="#ededed"]`[/color]use[color="#ededed"]`[/color]old[color="#ededed"]`[/color]parent[color="#ededed"]`[/color]dir
                    """
                    dir=md5dir(self.subdir,url,parent_url)
                    if[color="#ededed"]`[/color]dir==None:
                            print[color="#ededed"]`[/color]'md5dir[color="#ededed"]`[/color]came[color="#ededed"]`[/color]back[color="#ededed"]`[/color]with[color="#ededed"]`[/color]none!'
                            sys.exit()
                    #print[color="#ededed"]`[/color]"\twgetting[color="#ededed"]`[/color]%s"[color="#ededed"]`[/color]%[color="#ededed"]`[/color]url

                    #[color="#ededed"]`[/color]Retrieval[color="#ededed"]`[/color]of[color="#ededed"]`[/color]images[color="#ededed"]`[/color]from[color="#ededed"]`[/color]yahoo[color="#ededed"]`[/color]doesn't[color="#ededed"]`[/color]use[color="#ededed"]`[/color]the[color="#ededed"]`[/color]printer[color="#ededed"]`[/color]ready[color="#ededed"]`[/color]flag,[color="#ededed"]`[/color]html[color="#ededed"]`[/color]does
                    pr=self.printer_ready
                    if[color="#ededed"]`[/color]ignore_pr:
                            pr=''
                    wget_command[color="#ededed"]`[/color]=[color="#ededed"]`[/color]('/usr/bin/wget[color="#ededed"]`[/color][color="#ededed"]`[/color]-E[color="#ededed"]`[/color]-nv[color="#ededed"]`[/color]-H[color="#ededed"]`[/color]-k[color="#ededed"]`[/color]-p[color="#ededed"]`[/color]%s[color="#ededed"]`[/color]--no-host-directories[color="#ededed"]`[/color]--no-directories[color="#ededed"]`[/color]-P%s[color="#ededed"]`[/color]\"%s%s\"'[color="#ededed"]`[/color]%[color="#ededed"]`[/color](flag,dir,url,pr))
                    (status,output)=commands.getstatusoutput(wget_command)
                    if[color="#ededed"]`[/color](status>0):
                            self.pr[color="#ededed"]`[/color]("Wget[color="#ededed"]`[/color]failed![color="#ededed"]`[/color]\n\t%s"[color="#ededed"]`[/color]%[color="#ededed"]`[/color]output)
                            return()
                    #[color="#ededed"]`[/color]see[color="#ededed"]`[/color]what[color="#ededed"]`[/color]wget[color="#ededed"]`[/color]renamed[color="#ededed"]`[/color]the[color="#ededed"]`[/color]file[color="#ededed"]`[/color]as
                    try:
                            link=output.split('[color="#ededed"]`[/color]URL:')[1]
                            link=link.split('"')[1]
                            return(link)
                    except:
                            self.pr[color="#ededed"]`[/color]("WGET[color="#ededed"]`[/color]ERROR:\ncommand:\n%s\nURL:%s\n--\n%s\n--\nCould[color="#ededed"]`[/color]not[color="#ededed"]`[/color]determine[color="#ededed"]`[/color]new[color="#ededed"]`[/color]wget[color="#ededed"]`[/color]link:[color="#ededed"]`[/color]%s"[color="#ededed"]`[/color]%[color="#ededed"]`[/color](wget_command,url,output,sys.exc_info()[0]))
                            return('')
     
    Consider`its`equivalent`with`no`error`checking:
    Code (Text):

            def[color="#ededed"]`[/color]wget_link(self,url,flag,parent_url="",ignore_pr=False):
                    """
                    Download[color="#ededed"]`[/color]url[color="#ededed"]`[/color]and[color="#ededed"]`[/color]all[color="#ededed"]`[/color]requisite[color="#ededed"]`[/color]pages
                    First[color="#ededed"]`[/color]Create[color="#ededed"]`[/color]new[color="#ededed"]`[/color]dir[color="#ededed"]`[/color]or[color="#ededed"]`[/color]use[color="#ededed"]`[/color]old[color="#ededed"]`[/color]parent[color="#ededed"]`[/color]dir
                    """
                    dir=md5dir(self.subdir,url,parent_url)

                    #[color="#ededed"]`[/color]Retrieval[color="#ededed"]`[/color]of[color="#ededed"]`[/color]images[color="#ededed"]`[/color]from[color="#ededed"]`[/color]yahoo[color="#ededed"]`[/color]doesn't[color="#ededed"]`[/color]use[color="#ededed"]`[/color]the[color="#ededed"]`[/color]printer[color="#ededed"]`[/color]ready[color="#ededed"]`[/color]flag,[color="#ededed"]`[/color]html[color="#ededed"]`[/color]does
                    pr=self.printer_ready
                    wget_command[color="#ededed"]`[/color]=[color="#ededed"]`[/color]('/usr/bin/wget[color="#ededed"]`[/color][color="#ededed"]`[/color]-E[color="#ededed"]`[/color]-nv[color="#ededed"]`[/color]-H[color="#ededed"]`[/color]-k[color="#ededed"]`[/color]-p[color="#ededed"]`[/color]%s[color="#ededed"]`[/color]--no-host-directories[color="#ededed"]`[/color]--no-directories[color="#ededed"]`[/color]-P%s[color="#ededed"]`[/color]\"%s%s\"'[color="#ededed"]`[/color]%[color="#ededed"]`[/color](flag,dir,url,pr))
                    (status,output)=commands.getstatusoutput(wget_command)
                    #[color="#ededed"]`[/color]see[color="#ededed"]`[/color]what[color="#ededed"]`[/color]wget[color="#ededed"]`[/color]renamed[color="#ededed"]`[/color]the[color="#ededed"]`[/color]file[color="#ededed"]`[/color]as
                    link=output.split('[color="#ededed"]`[/color]URL:')[1]
                    link=link.split('"')[1]
                    return(link)
     
    It's`clearer.``Actually`the`essence`of`this`function`could`be`2`lines`without`error`checking`and`if`you`ask`the`caller`to`make`the`directory,`namely`just`a`wget`and`a`return`of`the`URL,`vastly`reducing`the`time`needed`to`figure`out`what`the`hell`is`going`on.``Also`you`really`only`need`2`arguments,`dir`and`url,`not`4.
     
    Last edited: Nov 8, 2006
  15. Nov 8, 2006 #14

    0rthodontist

    User Avatar
    Science Advisor

    Why can't I edit?

    Edit: I mean, why can't I post any Python code?
    Edit: I can if I replace the spaces with ededed-colored `'s...
     
    Last edited: Nov 8, 2006
  16. Nov 8, 2006 #15
    Now yet again, you are splitting hairs ...

    Focusing on that Python code you posted, that is a poor example to prove a point. The error handling is not filtering what kind of error it handles. Using the except command without any statement following it will direct any error to the excepted code block.

    If the code were written properly, it would be clear and concise as to what error it's excepting and handling. This is definitely more readable. To think otherwise is either ignorant, or just plain silly.
     
  17. Nov 8, 2006 #16

    0rthodontist

    User Avatar
    Science Advisor

    It would be a bit clearer if the type of the error were included, but that's not the main problem.

    Consider this function:
    Code (Text):

        def retrieve (self):
            try:
                mod=self.current.modified
            except:
                mod=''

            self.new = feedparser.parse(self.url,modified=mod)
            try:
                if self.new.status == 304:
                    self.pr ('\t304: no updates')
                    return()
            except:
                self.pr('No status variable... no internet access?')
                self.new.status=304
                return()
            if self.new.bozo>0:
                self.pr('Failed to retrieve (proper) rss feed:\n\t%s' %
                        (self.new.bozo_exception))

            if self.new.feed.has_key('lastbuilddate'):
                try:
                    self.new.lbd = time.strptime(self.new.feed['lastbuilddate'],"%a, %d %b %Y %H:%M:%S %Z")
                    self.pr('LBD of new feed %s' % (time.mktime(self.new.lbd)))
                except:
                    pass
                else:
                    try:
                        if time.mktime(self.current.lbd) == time.mktime(self.new.lbd):
                            self.pr ('\tLBD unchanged %s==%s' % (time.mktime(self.current.lbd),time.mktime(self.new.lbd)))
                            self.new.status=304
                            return()
                    except:
                        self.pr ('\tNo LBD key in current: %s' % sys.exc_info()[0])
                       
            #self.pr ('\tstatus: %d ' % self.new.status)
            self.pr ('\tEntries retrieved: %d' % len(self.new.entries))
            # number the entries for renaming the link in the updates subroutine
            ind=0
            for x in self.new.entries:
                x.index=ind
                ind+=1
     
    Without error handling (and removing some extraneous code), this is one line (whited out so you can read the function as written first):
    return feedparser.parse(self.url,modified=mod)
    Is it easier to understand if you see that one line, or see all the error handling?
     
    Last edited: Nov 8, 2006
  18. Nov 8, 2006 #17

    chroot

    User Avatar
    Staff Emeritus
    Science Advisor
    Gold Member

    So... why doesn't the author just put that "one-liner" in his comments above the code? Then you know exactly what the "gist" of the block is -- that's what this is all about, right? -- and the error-handling code stays put, interwoven with the code it protects, as it should be.

    And, besides, the code you pasted does NOT just download a page -- it checks server status codes, timestamps, and does other things. I agree it's poorly written code, but even without error-handling, it won't be just one line. You're being dishonest.

    - Warren
     
    Last edited: Nov 8, 2006
  19. Nov 8, 2006 #18
    In my opinion ...

    The error handling is very important. It'll tell whoever's reading your code what crap not to throw its way. If you really feel like achieving a sense of readability, I'll tell you what...

    At the top of the function, include a """ multiline comment """ that contains the code without error handling. Otherwise, your intentions in compromising length of code for a secure algorithm is unjustified.

    Edit : Wow. A pleasant surprise: chroot and I both suggested the exact same thing. Comment yer "readable" code if it makes such a difference.
     
  20. Nov 8, 2006 #19

    chroot

    User Avatar
    Staff Emeritus
    Science Advisor
    Gold Member

    Bingo. That's two of us, who have independently said the same thing.

    - Warren
     
  21. Nov 8, 2006 #20

    0rthodontist

    User Avatar
    Science Advisor

    No, it really is. There's no need to check the last build date because if there wasn't a 304, it will always be different. Also the index code doesn't actually do anything since the index already contains those values (not that you need them anyway since you can just iterate through the feeds). All the rest is just error handling--necessary, but obfuscating. Well, there's also the "mod" variable, but still the only reason you had to make that is because you didn't know if the current feed had a modified field, so its purpose is still entirely error handling.
     
    Last edited: Nov 8, 2006
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook

Have something to add?



Similar Discussions: I hate error handling
  1. Exception Handling (Replies: 7)

  2. I logical error? (Replies: 8)

Loading...