Replace Exceptions With Defaults

December 1, 2017

All programming languages provide ways to handle exceptions, and all programs should be careful to handle exceptions properly; it’s good programming practice to keep exceptions from interfering with the normal conduct of your program, and courteous to your users. A good way to handle exceptions is to replace them with default values. Consider this:

> (car '())
Exception in car: () is not a pair
> (try (car '()) #f)
#f

The first exception is unhandled, and displays an error to the user. The second exception is handled, and converts the error to a default value. Replacing exceptions with defaults makes programs more robust.

Your task is to devise a simple system of replacing exceptions with defaults in your favorite programming language. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Advertisement

Pages: 1 2

5 Responses to “Replace Exceptions With Defaults”

  1. chaw said

    Below are my procedural and syntactic interpretations of the idea.
    The syntactic version puts the default first, before the body of
    expressions, because I thought that a bit nicer, though it is easy to
    change.

    (import (scheme base)
            (scheme write))
    
    (define (make-try/default proc dflt)
      (lambda args
        (guard (exc (else dflt))
          (apply proc args))))
    
    (define-syntax try/default
      (syntax-rules ()
        ((_  dflt body body1 ...)
         ((make-try/default (lambda () body body1 ...) dflt)))))
    
    (define (test)
      (define car/default (make-try/default car 42))
      (display (map car/default '((2 3 5) (2) ())))
      (newline)
      (display (try/default '(4 2 42)
                 (define lst '(2 3 5))
                 (map car (list lst '(2) '()))))
      (newline))
    
    (test)
    

  2. programmingpraxis said

    @chaw: Your version fails because it evaluates the default expression even when it is not needed. Here is output from my macro, at the top, and your macro/procedure, at the bottom:

    > (try (car '(2)) (begin (display "hello") (newline) 3))
    2
    > (try/default (begin (display "hello") (newline) 3) (car '(2)))
    hello
    2

    Both programs correctly evaluate to the car of the list. But your program also prints “hello” as a side-effect of evaluating the default expression, which it should not do.

    You can run the program at https://ideone.com/9ajhyO.

  3. Daniel said

    Here’s a solution in Python.

    The default value is specified using a lambda. This provides deferred evaluation to address the issue that @programmingpraxis mentions in an earlier comment (so that the default is only evaluated when needed).

    The function returns a second value that indicates whether the expression was evaluated successfully.

    def trydefault(expr, default):
        try:
            output = expr()
            success = True
        except:
            output = default()
            success = False
        return output, success
    
    l = []
    element, _ = trydefault(lambda: l[0], lambda: None)
    print element
    

    Output:

    None
    
  4. John Cowan said

    I disagree that this is in any way good practice. If you are passing a non-pair to car, it should fail immediately and loudly, as something is severely wrong. Changing it to #f just postpones the evil day and makes the error harder to debug.

    That said, long-running programs do need to catch exceptions so as to remain long-running, and the Nulll Object pattern (which returns an object of the correct type with no contents rather than a generic nil) is perfectly good even in Lisps.

  5. programmingpraxis said

    @John: I used (car ‘()) as an example. I would not handle type errors that way in practice. The text makes clear that this is a mechanism for handling some types of exceptions, not as a way to bypass real errors. For instance, if a binary tree lookup doesn’t find an expected key, this mechanism can replace the exception with some default value so the program can continue.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: