Error Handling Common Lisp has the throw/catch statements so that you can simulate exception handling as seen in languages like Java But CL goes far beyond.

Slides:



Advertisements
Similar presentations
Topics Introduction Types of Errors Exceptions Exception Handling
Advertisements

Some non-recursive tricks. The Lambda expression. More on Let, Let*, apply and funcall.
ANSI Common Lisp 5. Control 16 June Blocks -- progn progn > (progn (format t “a”) (format t “b”) ( )) ab 23 The expressions within its body.
Exception Handling Chapter 15 2 What You Will Learn Use try, throw, catch to watch for indicate exceptions handle How to process exceptions and failures.
An Introduction to Java Programming and Object- Oriented Application Development Chapter 8 Exceptions and Assertions.
C++ Programming: Program Design Including Data Structures, Fourth Edition Chapter 15: Exception Handling.
JAVA: An Introduction to Problem Solving & Programming, 6 th Ed. By Walter Savitch ISBN © 2012 Pearson Education, Inc., Upper Saddle River,
Chapter 16: Exception Handling C++ Programming: From Problem Analysis to Program Design, Fifth Edition.
Objectives In this chapter you will: Learn what an exception is Learn how to handle exceptions within a program See how a try / catch block is used to.
© The McGraw-Hill Companies, 2006 Chapter 15. © The McGraw-Hill Companies, 2006 Exceptions an exception is an event that occurs during the life of a program.
Exception Handling Part 1: Handing Java Exceptions CSIS 3701: Advanced Object Oriented Programming.
C++ Programming: From Problem Analysis to Program Design, Third Edition Chapter 16: Exception Handling.
1 Lecture 11 Interfaces and Exception Handling from Chapters 9 and 10.
Exception Handling Introduction Exception handling is a mechanism to handle exceptions. Exceptions are error like situations. It is difficult to decide.
CSI 3120, Exception handling, page 1 Exception and Event Handling Credits Robert W. Sebesta, Concepts of Programming Languages, 8 th ed., 2007 Dr. Nathalie.
11-Jun-15 Exceptions. 2 Errors and Exceptions An error is a bug in your program dividing by zero going outside the bounds of an array trying to use a.
ITERATIVE CONSTRUCTS: DOLIST Dolist is an iterative construct (a loop statement) consisting of a variable declaration and a body The body states what happens.
16-Jun-15 Exceptions. Errors and Exceptions An error is a bug in your program dividing by zero going outside the bounds of an array trying to use a null.
Exceptions in Java Fawzi Emad Chau-Wen Tseng Department of Computer Science University of Maryland, College Park.
Exceptions. Errors and Exceptions An error is a bug in your program –dividing by zero –going outside the bounds of an array –trying to use a null reference.
© Copyright Eliyahu Brutman Programming Techniques Course Version 1.0.
Exceptions Objectives At the conclusion of this lesson, students should be able to Explain the need for exceptions Correctly write programs that use.
1 Exception and Event Handling (Based on:Concepts of Programming Languages, 8 th edition, by Robert W. Sebesta, 2007)
Java Software Solutions Foundations of Program Design Sixth Edition
Chapter 13 Exception Handling F Claiming Exceptions F Throwing Exceptions F Catching Exceptions F Rethrowing Exceptions  The finally Clause F Cautions.
June 14, 2001Exception Handling in Java1 Richard S. Huntrods June 14, 2001 University of Calgary.
1 Chapter Eight Exception Handling. 2 Objectives Learn about exceptions and the Exception class How to purposely generate a SystemException Learn about.
Object Oriented Programming
Chapter 12: Exception Handling
And other languages…. must remember to check return value OR, must pass label/exception handler to every function Caller Function return status Caller.
1 CSC241: Object Oriented Programming Lecture No 27.
WEEK EXCEPTION HANDLING. Syntax Errors Syntax errors, also known as parsing errors, are perhaps the most common kind of complaint you get while.
Control Structures We have already visited some of the control structures (if, if-else, dolist, dotimes) –Here we take a more in-depth look at control.
CMSC 202 Exceptions. Aug 7, Error Handling In the ideal world, all errors would occur when your code is compiled. That won’t happen. Errors which.
VB.Net - Exceptions Copyright © Martin Schray
Chapter 14: Exception Handling. Objectives In this chapter, you will: – Learn what an exception is – Learn how to handle exceptions within a program –
Exception Handling Unit-6. Introduction An exception is a problem that arises during the execution of a program. An exception can occur for many different.
Exceptions in Java. Exceptions An exception is an object describing an unusual or erroneous situation Exceptions are thrown by a program, and may be caught.
The Loop Macro Many of the CL “functions” are actually macros (let, progn, if, etc) The most complicated macro in CL is probably the Loop macro –The Loop.
JAVA: An Introduction to Problem Solving & Programming, 5 th Ed. By Walter Savitch and Frank Carrano. ISBN © 2008 Pearson Education, Inc., Upper.
The Debugger and Inspector Two very useful tools available in Common Lisp are the debugger and inspector –Using them is partially implementation dependent,
Cem Sahin CS  There are two distinguishable kinds of errors: Python's Errors Syntax ErrorsExceptions.
Sheet 3 HANDLING EXCEPTIONS Advanced Programming using Java By Nora Alaqeel.
Exceptions, handling exceptions & message boxes Year 11 Information Technology.
Exceptions and Assertions Chapter 15 – CSCI 1302.
CSE 332: C++ Statements C++ Statements In C++ statements are basic units of execution –Each ends with ; (can use expressions to compute values) –Statements.
Exception Handling in Java Topics: Introduction Errors and Error handling Exceptions Types of Exceptions Coding Exceptions Summary.
11. EXCEPTION HANDLING Rocky K. C. Chang October 18, 2015 (Adapted from John Zelle’s slides)
Chapter 15: Exception Handling C++ Programming: Program Design Including Data Structures, Fifth Edition.
Control Structures CSC 358/ Outline Midterm Lab #3 Homework #4 Sequential structures Conditional structures Unconditional branching Iteration.
(c) University of Washington10-1 CSC 143 Java Errors and Exceptions Reading: Ch. 15.
Exceptions Lecture 11 COMP 401, Fall /25/2014.
JavaScript and Ajax (Control Structures) Week 4 Web site:
ECE122 L23: Exceptions December 6, 2007 ECE 122 Engineering Problem Solving with Java Lecture 24 Exceptions.
Introduction to Exceptions in Java CS201, SW Development Methods.
FILES AND EXCEPTIONS Topics Introduction to File Input and Output Using Loops to Process Files Processing Records Exceptions.
CSE 332: C++ Exceptions Motivation for C++ Exceptions Void Number:: operator/= (const double denom) { if (denom == 0.0) { // what to do here? } m_value.
Eighth Lecture Exception Handling in Java
Testing and Debugging.
Why exception handling in C++?
Chapter 14: Exception Handling
Throwing and catching exceptions
Part B – Structured Exception Handling
Exceptions.
Problems Debugging is fine and dandy, but remember we divided problems into compile-time problems and runtime problems? Debugging only copes with the former.
Exceptions 10-May-19.
Common Lisp II.
CMSC 202 Exceptions.
Exception Handling.
Presentation transcript:

Error Handling Common Lisp has the throw/catch statements so that you can simulate exception handling as seen in languages like Java But CL goes far beyond this by providing a number of alternative mechanisms –you can use throw/catch or return-from but include an unwind-protect so that specific operations happen no matter if you branch or not –you can specify an error that terminates the execution of the program –you can specify an error that drops you in the debugger –you can specify an error that drops you in the debugger and includes a specialized restart –you can define conditions (same as Exceptions in Java) and then there are several ways to handle conditions including specialized restarts Why all the different approaches? –in part, the CL philosophy is one of giving you as many tools as possible however, CL differs from most languages in that you have the interactive environment, so using the debugger becomes another weapon in your programming arsenal –the idea of branching to an exception handler, as performed in Java, is both limiting and may lead to continuation problems, CL tries to do better

Catch/Throw vs. Return-from Throw can be used to transfer control to the most recent catch statement that has a matching symbol –this allows you to escape from a potentially erroneous situation but has two problems throw unwinds the stack to the point where the catch is found finding the proper catch is done dynamically, so there is no way to necessarily know where control will transfer when writing the code –return-from is preferred because it can be used to terminate the function and return control to the calling unit In either case, any remaining instructions in the function or block are ignored –we may want to force those instructions to execute (such as a close statement) and so we would use unwind-protect to surround the code with the error and the clean-up code

Unwind Protect Unwind-protect executes the next instruction and then guarantees that code that follows the next instruction inside the unwind-protect will execute no matter if the instruction tries to leave the block through some branch –such as through a throw or return-from typically the next instruction will be a function call or a progn statement that permits multiple operations This will be helpful when some concluding statement(s) should be assured of running, such as closing a file Form: (unwind-protect (progn ;; statements go here ) (;; statements here will automatically be executed) (;; and more statements will be executed) (;; and so on))

Example (defun fn-a ( ) (catch 'fn-a (print 'before-fn-b-call) (fn-b) (print 'after-fn-b-call))) (defun fn-b ( ) (print 'before-fn-c-call) (fn-c) (print 'after-fn-c-call)) (defun fn-c ( ) (print 'before-throw) (throw 'fn-a 'done) (print 'after-throw)) If we call fn-a, we get: BEFORE-FN-B-CALL BEFORE-FN-C-CALL BEFORE-THROW DONE If we change fn-b to be (defun fn-b ( ) (unwind-protect (progn (print 'before-fn-c-call) (fn-c)) (print 'after-fn-c-call))) We get BEFORE-FN-B-CALL BEFORE-FN-C-CALL BEFORE-THROW AFTER-FN-C-CALL DONE

Another Example (defun compute-average (filename) (let (infile (count 0) (sum 0) avg (status t)) (unwind-protect (progn (setf infile (open filename)) (setf status (do ((temp (read infile nil nil) (read infile nil nil))) ((null temp) temp) (setf count (+ count 1)) (setf sum (+ sum temp))))) (if (null status) (if (> count 0) (setf avg (/ sum count)) (setf avg (format nil "File ~A empty" filename))) (setf avg (format nil "Error in File ~A occurred" filename))) (close infile)) avg)) We will exit this loop prematurely if either there is an error reading the file or the file is not found Status gets temp, whatever the last thing was that was read in – it should be nil Status is then used in the protect portion

Error The error instruction causes a program to terminate at that point and return an error message –you can provide a tailored error message for the given circumstance your output statement is like a format in that it can contain various ~ arguments followed by variables –since this instruction terminates the program, a continuation/restart is not possible – you are dropped in the debugger with abort options only Examples: (defun reciprocal (x) (if (= x 0) (error "Cannot divide by 0") (/ 1 x))) (defun count0 (lis) (let ((num 0)) (dolist (a lis) (if (not (numberp a)) (error "List contains non-numeric item ~A" a) (if (= a 0) (setf num (+ num 1))))) num)) (reciprocal 0) Error: Cannot divide by 0 1 (abort) Return to level 0. 2 Return to top loop level 0.

Cerror cerror is a superior version which also drops you in the debugger, but unlike error (or break), cerror –gives you the ability to specify your own continuation message (if desired) so that you can restart the program from this point –note that the restart just goes on to the next instruction Form: (cerror “restart message” “error message” params) –the parameters refer to any ~var items in either message –continuation must be part of the code, that is, you cannot provide a list of possible restarts, instead it just continues (defun count0 (lis) (let ((num 0)) (dolist (a lis) (if (not (numberp a)) (cerror "Skip ~A and continue" "List contains non-numeric item ~A" a) (if (= a 0) (setf num (+ num 1))))) num)) CL-USER 86 > (count0 '(1 0 a 3 0 4)) Error: List contains non-numeric item A 1 (continue) Skip A and continue 2 (abort) Return to level 0. 3 Return to top loop level 0. CL-USER 87 : 1 > :c 1 2

Assertions An assertion is similar to cerror except that you can permit the user to submit replacement values Form: (assert test (value(s)) &optional “message”) –the message is like what we had in error or cerror, without it, the message is not necessarily useful for a non-programmer If the test fails, then CL drops into the debugger and the user has a chance to enter a new value (values) as specified in the list –examples: (defun reciprocal (x) (assert (not (= 0 x)) (x)) (/ 1 x)) CL-USER 51 > (reciprocal 0) Error: The assertion (NOT (= 0 X)) failed. 1 (continue) Retry assertion with new value for X. 2 (abort) Return to level 0. 3 Return to top loop level 0. (defun reciprocal (x) (assert (not (= 0 x)) (x) “Cannot divide by 0, replace x”) (/ 1 x)) The list can contain multiple variables in which case the user is asked to input new values for all of them

Assertion Example Consider as an example that we want to take two values and ensure that they are non-negative numbers Here is a function to accomplish this: (defun test-values (a b) (assert (and (numberp a) (numberp b)) (a b)) (assert (and (>= a 0) (>= b 0)) (a b)) (list a b)) (test-values -5 'a) Error: The assertion (AND (NUMBERP A) (NUMBERP B)) failed. 1 (continue) Retry assertion with new values for A, B. 2 (abort) Return to level 0. 3 Return to top loop level 0. CL-USER 3 : 1 > :c 1 Enter a form to be evaluated: [pop-up window asks to replace a] -5 Enter a form to be evaluated: [pop-up window asks to replace b] -4 Error: The assertion (AND (>= A 0) (>= B 0)) failed. 1 (continue) Retry assertion with new values for A, B. 2 (abort) Return to level 0. 3 Return to top loop level 0. CL-USER 4 : 1 > :c 1 Enter a form to be evaluated: [pop-up window for a] 5 Enter a form to be evaluated: [pop-up window for b] 4 (5 4)

Defining Conditions As in Java, conditions in CL are objects –You define a class for a specific type of condition –Condition objects include slots like with objects slots can include arguments like initarg, initform, accessor, etc –Conditions can inherit from other conditions –Aside from slots, a condition can also include a :report clause which will be used as output when the condition is raised :documentation clause (define-condition my-error (condition) ((error-type :initarg :error-type :initform "Unknown" :accessor error-type) (error-location :initarg :error-location :initform "Unknown" :accessor error-location)) (:report (lambda (condition stream) (format stream "Condition ~A arose in ~A location" (error-type condition) (error-location condition))))) (error 'foo :error-type "Mistake") would generate the message Condition Mistake arose in Unknown location

Handling the Condition As seen with the previous example, the condition can be raised explicitly through an error message –this drops the program into the debugger, but the user’s only restart choice is to abort the program The condition can also be raised through cerror, where the programmer can specify what restarting will do –here is a revised reciprocal function that will raise the my-error condition and still let the user continue (defun reciprocal (x) (when (= x 0) (cerror "Use 1 in place of 0 for input" 'my-error :error-type "Division by zero" :error-location "in function reciprocal") (setf x 1)) (/ 1 x)) CL-USER 89 > (reciprocal 0) Condition Division by zero arose in in function reciprocal location 1 (continue) Use 1 in place of 0 for input 2 (abort) Return to level 0. 3 Return to top loop level 0. CL-USER 90 : 1 > :c 1 1

More Elaborate Continuation The previous example forced the user to accept x = 1 if they wanted to continue –Can we improve on this? –The cerror command only allows for 1 continuation, but we can be more elaborate in what happens with that continuation code (defun reciprocal (x) (when (= x 0) (cerror "Input a new value in place of 0" 'my-error :error-type "Division by zero" :error-location "in function reciprocal") (format t "~%Enter new value: ") (setf x (read))) (/ 1 x)) CL-USER 57: > (reciprocal 0) Condition Division by zero arose in in function reciprocal location 1 (continue) Input a new value in place of 0 2 (abort) Return to level 0. 3 Return to top loop level 0. CL-USER 58 : 1 > :c 1 Enter new value: 5 1/5

Condition Handlers The standard form of a condition handler is through the handler-bind macro –we are used to seeing try-catch blocks in something of this form in Java (C++ is similar): { … try {…} catch(ExceptionType e) {…} –in Common Lisp, the catch is made through handler-bind, and the try block is embedded into this block of code –(handler-bind ((condition-name #’(lambda (x) ;; code goes here to handle the condition))) ;; code goes here equivalent to the try block) –the code after the ))) will can contain signal statements that can signal the given condition, in which case control is transferred to that chunk of code –to signal a condition: (signal ’condition-name) the signal instruction can also include accessor or initarg arguments such as (signal ’my-error :error-type “Help I’m lossed” :error-location “my- function”)

Example (defun my-divider (a b) (if (and (= a 0) (= b 0)) (signal 'my-error :error-type "0 / 0 Does not exist" :error-location "my-divider") (if (= b 0) (signal 'my-error :error-type "Division by zero" :error-location "my-divider") (/ a b)))) (defun safe-divider (a b) (handler-bind ((my-error #'(lambda (x) (format t "~A. How should we proceed?~%1. Return 0.~%2. Input new value for denominator.~%3. Input new values for numerator and denominator.~%Select: " x) (let ((temp (read))) (cond ((= temp 1) (return-from safe-divider 0)) ((= temp 2) (format t "Enter new denominator: ") (setf b (read))(return-from safe-divider (my-divider a b))) ((= temp 3) (format t "Enter new numerator: ") (setf a (read)) (format t "Enter new denominator: ") (setf b (read)) (return-from safe-divider (my-divider a b))) (t (return-from safe-divider nil))))))) (my-divider a b)))

How This Differs From Java In a language like Java, an exception handler –contains the mechanism for handling the exception –its location dictates continuation for instance, consider that method handle1 has a try/catch block that can catch Exception Foo –handle1 calls method handle2, which throws Foo –handle2 calls error3 which throws Foo –if a Foo exception arises in handle2, handle2 transfers control back to handle1 to solve the problem, handle1 then continues – this is what we might expect –if a Foo exception arises in error3 then error3 throws to handle2 which throws to handle1 –should handle2 have been aborted because of an exception in error3? –in Common Lisp, since the handler was part of the handler- bind, restart will (or can) occur in the instruction after the call that produced the signal in our previous example, this was not the case because of the use of return-from statements

Handler-Case Handler-bind allows you to handle a situation without removing items from the stack –But unfortunately, it is somewhat complex to use Handler-case is a simpler condition handler –Form: (handler-case (;; code here that might cause a condition) (condition1 (param) ;;condition1 handler) (condition2 (param) ;; condition2 handler) …) –Example: (handler-case (progn (print (/ b a)) (print (/ b c))) (division-by-zero (x) (print 'oops))) Here assume that a, b and c are variables equal to different values If a or c are 0, then control transfers to the error handler Notice that conditions can be built-in or user-defined

Restart Handlers Handler-case unwinds the stack to the point where the handler-case is found –so this is of less use than handler-bind Restart-case is a version of handler-case does not try to handle the condition but instead –drops you in the debugger –however, the restart-case allows you to specify restart options that the user can select between since we generally want to shelter a user from the debugger, we may not want to handle conditions in this way A variation is invoke-restart –when provided with a function name as a symbol, it will find the most recently bound version of that restart (that is, the one nearest on the run-time stack) and resume execution we are going to skip the details of the restart forms since they get more and more complicated!

And Finally… Using signal outside of a handler macro will result in the condition being raised but not handled, so you will just get a nil return value –Error and Cerror call signal for you by the way Warn is like error or cerror in that it signals the condition, but rather than being dropped in the debugger, if signal returns then execution continues from that point –this allows you to perform the operation of a condition handler without having to worry about restarts A built-in restart is called continue, which merely resumes (this would be equivalent to using warn instead of error or cerror) –the Practical Common Lisp on-line text has more detail, read it if you are interested!