1 / 24

CS 3304 Comparative Languages

Explore the concept of exceptions in programming languages, including their detection, raising, and handling. Learn about different exception handling mechanisms and their benefits in error handling.

smcwhorter
Télécharger la présentation

CS 3304 Comparative Languages

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CS 3304Comparative Languages • Lecture 14:Exceptions, Coroutines and Events • 1 March 2012

  2. Exception • Exception: an unexpected – or at least unusual – condition that arises during program execution, and that cannot easily be handled in the local context: • Detected automatically by the language implementation. • Program may raise it explicitly. • The most common exceptions: various run-time errors: • “Invent” a value that can be used by the caller when a real value could not be returned. • Return an explicit “status” value to the caller, who must inspect it after every call (extra parameter in a global variable or encoded as otherwise invalid but patterns of function’s regular return value). • Rely on the caller to pass a closure (if supported) for an error-handling routine the normal routine can call when it runs into trouble.

  3. Exception Handling • Exception handling mechanism moves error-checking code “out of line”: • Allows the normal case to be specified simply. • Arranges for control to branch to an exception handler when appropriate. • What is an exception handler? • Code executed when exception occurs. • May need a different handler for each type of exception. • Why design in exception handling facilities? • Allow user to explicitly handle errors in a uniform manner. • Allow user to handle errors without having to check these conditions. • Explicitly in the program everywhere they might occur.

  4. PL/I Exception Handling • Pioneered by PL/I: statements of a form:ON conditionstatement • The nested statement is a is handler that is “remembered” and executed later if exception condition arises. • The binding of handlers to exception depends on the flow control at run time. • If handler returns, program terminates or resumes at following the place where exception occurred. • Experience with PL/I indicates that both the dynamic binding of handlers to exceptions and the automatic resumption of code in which an exception occurred are confusing and error prone.

  5. More Recent Languages • Handlers are lexically bound to blocks: the handler execution replaces the yet-to-be-completed portion of the block. • If an exception is not handled within the current subroutine, the subroutine returns abruptly (exceptional return) and the exception is raised at the point of call. • If not handled, it propagates back up the dynamic chain. • The handler is lexically bound to the expression or statement that calls the called routine. • Three kinds of operations performed by exception handlers: • Compensate for the exception in a way that allows the program to recover and continue execution. • If not handled locally, declare a local handler that “cleans” and reraises the exception. • If recovery not possible, a handler prints a helpful message before the program terminates.

  6. Multilevel Returns • A subroutine that performs a multilevel return is functioning as expected. • A subroutine that raises an exception is not functioning as expected. • In most languages, a multilevel return requires the outer caller to provide a trivial caller. • Common Lisp is providing four different versions of its exception-handling mechanism: • Two provide the usual “exceptional return” semantics. • Two are designed to repair problem and restart evaluation of some dynamically enclosing expression. • Orthogonally, two perform their work in the referencing environment where the handler is declared and two perform their work in the environment where the exception first arises.

  7. Defining Exceptions • Dynamic semantic errors usually automatically result in exceptions which the program can then catch. • Predefined exceptions include arithmetic overflow, division by zero, end-of-file on input, subscript and subrange errors, null pointer reference: • They may arise in certain valid programs. • Other dynamic errors (return from a subroutine that has not yet designated a return value): still fatal in most languages. • C++, Common Lisp: all programmer defined. • Ada: some of the predefined exceptions can be suppressed using a pragma. • Ada, Modula-3, most OO languages: an exception is an instance of some predefined or user defined type.

  8. Exception Propagation • A block of code can have a list of exception handlers. • When an exception arises, the handlers are examined in order and the control is transferred to the first one that matches the exception: • C++: a handler matches if it names a class from which the exception is derived. • Exception handler declared in a recursive subroutine: caught by the innermost handler for that exception at run time: • If the exception propagates out of the scope in which it was declared, it can no longer be named by a handler and is caught only by a “catch-all” handler. • Language with concurrency: • Modula-3: the entire programs terminates abnormally. • Ada, Java: the affected thread terminates quietly.

  9. Handlers on Expressions • ML, Common Lisp: an exception handler is attached to an expression, rather than to a statement: • In ML:val foo = (f(a) * b) handle Overflow => max_int; • (f(a) * b) is the protected expression. • Overflow is a predefined exception • max_int is an expression whose value replaces the value of the expression in which the Overflow exception arose. • Both the protected expression and the handler could in general be arbitrarily complicated, with many nested subroutine calls. • Exceptions that arise within a nested call (and not handled locally) propagate back down the dynamic chain.

  10. Cleanup Operations • When searching for a matching handler, the exception-handling mechanism must “unwind” the run-time stack by reclaiming the stack frames of any subroutine from which the exception escapes. • C++: when leaving a scope, call destructor functions for any objects declared within that scope. • Common Lisp: provided by unwind-protect expression. • Modula-3, Python, Java, C#: provided by try… finally construct. Modula-3 example:TRY my Stream := OpenRead(myFileNmae); Parse(mySTream);FINALLY Close(myStream);END;

  11. Implementation of Exceptions • A linked-list stack of handlers. • When control enters a protected block, the handler for that block is added to the head of the list. • When an exception arises, the language run-time system pops the innermost handler off the list and calls it. • The handler begins by checking to see if it matches the exception that occurred – if not, it simply reraises it. • To implement propagation back down the dynamic chain, each subroutine has an implicit handler that performs the work of the subroutine epilogue code and then reraises the exception. • The only real purpose of the handler list is to determine which handler is active.

  12. Exception Handling without Exceptions • Exceptions can be simulated in a language that does not provide them as built-in. • Using labels/goto: Pascal, Algol 60, PL/I. • Scheme provides a general-purpose function called call-with-current-continuation (call/cc). • Takes a single argument f, which is itself a function. • It calls f, passing as an argument a continuation c (a closure). • ccan be saved in variables, returned explicitly by subroutines, or called repeatedly, even after control has returned from f. • Sufficient to build a wide variety of control abstractions, including iterators and coroutines. • C: provides a pair of library routines, setjmp and longjmp. • Implemented by saving the current machine registers in the setjmp buffer, and by restoring them in longjmp. • C allows the programmer to specify certain variables as volatile.

  13. Coroutines • Coroutines are execution contexts that exist concurrently, but that execute one at a time, and that transfer control to each other explicitly, by name. • Coroutines can be used to implement: • Iterators (Section 6.5.3). • Threads (to be discussed in Chapter 12). • Coroutines uses transfer operation: saves the current program counter in the current coroutine object and resumes the coroutine specified as a parameter. • The main body of the program plays the roles of an initial, default coroutine.

  14. Stack Allocation • Because they are concurrent (i.e., simultaneously started but not completed), coroutines cannot share a single stack. • If all coroutines are declared at the outer most level of lexical nesting, the stack are entirely disjoint. • Each coroutine could be given a fixed amount of statically allocated stack space (overflow or space waste). • Stack frames could be allocated from the heap (Lisp, Scheme): avoids overflow and internal fragmentation. • Stack could be allocated in large, fixed size chunks. • Subroutine could use the ordinary stack if the compiler can verify that they will not perform a transfer before returning.

  15. Cactus Stack • Used when two or more corutines are declared in the same nonglobal scope: they must share access to objects in that scope. • Example: The main stack (MQR) and the coroutinesA, B, C and D. • Each branch off the stackcontains the frames of aseparate coroutine. • The dynamic chain of agiven coroutine ends in theblock in which coroutinebegan execution. • The static chain extendsdown into the remainder ofthe cactus.

  16. Transfer • Requires run-time system to change program counter (PC), the stack, and the content of the processor’s registers: encapsulated in the transfer operation. • Changing PC from one coroutine to another means remembering the right return address: if transfer saves it return address in the stack, then the PC will change automatically as a side effect of changing stacks.

  17. Implementing Iterators • One coroutine is used to represent the main program, a second is used to represent the iterator: • Additional coroutines may be needed if iterators nest. • Coroutines are overkill for iterators implementation. • Single stack implementation: • Because a given iterator is always resumed at the same place in the code, the subroutine call stack will always contain the same frames whenever the iterator runs. Since yield statements can appear only in the main body of the iterator, it will be the same frame. • Data structure implementation: • C#1.1: provides iterator objects that implement the IEnumerator interface, which provides MoveNext and Current methods. • C# 2.0: true iterators as an extension of iterator objects. Declare a method that contains one or more yield return statements, and whose return type is IEnumerator or IEnumerable.

  18. Discrete Event Simulation • One of the most important applications of coroutines. • A discrete event simulation is one in which the model is naturally expressed in terms of events that happen at specific times. • Each active object is represented with a coroutine. • Each object keeps track of its own state. • If each active object can tell when it will next do something interesting, then we can determine which objects will interact next by keeping the currently inactive coroutines in a priority queue, ordered by the time of their next event.

  19. Events • Event is something to which a running program needs to respond but which occur outside the program, at an unpredictable time (e.g., inputs to GUI). • Synchronous input is generally not acceptable. • An event handler (callback) is invoked (asynchronously) when a given event occurs. • Then run-time system calls back into the program instead of being called from it.

  20. Sequential Handlers • A program must register and provide the handles to be invoked when the event occurs. • The device’s activity during program’s execution triggers an interrupt mechanism that saves program’s registers and invokes the event handler. • This can be implemented using the Unix signal mechanism. • The language run-time library contains a block of code known as the signal trampoline and a buffer writable by the kernel and readable by the runtime. • The trampoline creates a frame for itself in the stack and then calls the event handler using the normal subroutine calling sequence. • To avoid recursive events, some signals may be disabled.

  21. Thread-Based Handlers • Events are often handled by a separate thread of control, rather than by a spontaneous thread of control. • The handler thread makes a system call to request the next event and waits for it to occur. • Handling multiple events concurrently may require multiple handler threads. • To avoid recursive events disabling some signals may not be sufficient, a full-fledged synchronization mechanism is required. • Many contemporary GUI systems are thread-based.

  22. Main Event Loop • Event programming follows a more iterative path, unlike traditional sequential:while ( ! Button() );versuswhile ( ! Event() );

  23. Event Types • Two groups: low-level events and semantic events. • Low-level events represent window-system occurrences or low-level input. • Examples of low-level events include mouse and key events both of which result directly from user input. • Semantic events: everything else. • Examples of semantic events include action and item events. A semantic event might be triggered by user input; however, some semantic events are not triggered by low-level events. For example, a table-model event might be fired when a table model receives new data from a database. • Whenever possible, you should listen for semantic events rather than low-level events. That makes your code as robust and portable as possible.

  24. Summary • Exception handling mechanisms allow a program to “unwind” in a well-structures way from a nested sequence of subroutine calls. • Coroutines allow a program to maintain (and switch between) two or more execution contexts. • Events allow a program to respond to asynchronous external activity.

More Related