Changeset 9373b6a


Ignore:
Timestamp:
Aug 9, 2021, 3:46:57 PM (16 months ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
5438e41, e5aba4a
Parents:
478c610 (diff), b0b89a8 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/andrew_beach_MMath/features.tex

    r478c610 r9373b6a  
    1616throw/catch as a particular kind of raise/handle.
    1717These are the two parts that the user writes and may
    18 be the only two pieces of the EHM that have any syntax in the language.
     18be the only two pieces of the EHM that have any syntax in a language.
    1919
    2020\paragraph{Raise}
    21 The raise is the starting point for exception handling. It marks the beginning
    22 of exception handling by raising an exception, which passes it to
     21The raise is the starting point for exception handling
     22by raising an exception, which passes it to
    2323the EHM.
    2424
    2525Some well known examples include the @throw@ statements of \Cpp and Java and
    26 the \code{Python}{raise} statement from Python. In real systems a raise may
    27 preform some other work (such as memory management) but for the
     26the \code{Python}{raise} statement of Python. In real systems, a raise may
     27perform some other work (such as memory management) but for the
    2828purposes of this overview that can be ignored.
    2929
    3030\paragraph{Handle}
    31 The purpose of most exception operations is to run some user code to handle
    32 that exception. This code is given, with some other information, in a handler.
     31The primary purpose of an EHM is to run some user code to handle a raised
     32exception. This code is given, with some other information, in a handler.
    3333
    3434A handler has three common features: the previously mentioned user code, a
    35 region of code they guard and an exception label/condition that matches
    36 certain exceptions.
     35region of code it guards, and an exception label/condition that matches
     36the raised exception.
    3737Only raises inside the guarded region and raising exceptions that match the
    3838label can be handled by a given handler.
    3939If multiple handlers could can handle an exception,
    40 EHMs will define a rule to pick one, such as ``best match" or ``first found".
     40EHMs define a rule to pick one, such as ``best match" or ``first found".
    4141
    4242The @try@ statements of \Cpp, Java and Python are common examples. All three
    43 also show another common feature of handlers, they are grouped by the guarded
    44 region.
     43show the common features of guarded region, raise, matching and handler.
     44\begin{cfa}
     45try {                           // guarded region
     46        ...     
     47        throw exception;        // raise
     48        ...     
     49} catch( exception ) {  // matching condition, with exception label
     50        ...                             // handler code
     51}
     52\end{cfa}
    4553
    4654\subsection{Propagation}
    4755After an exception is raised comes what is usually the biggest step for the
    48 EHM: finding and setting up the handler. The propagation from raise to
     56EHM: finding and setting up the handler for execution. The propagation from raise to
    4957handler can be broken up into three different tasks: searching for a handler,
    5058matching against the handler and installing the handler.
     
    5260\paragraph{Searching}
    5361The EHM begins by searching for handlers that might be used to handle
    54 the exception. Searching is usually independent of the exception that was
    55 thrown as it looks for handlers that have the raise site in their guarded
     62the exception. The search is restricted to
     63handlers that have the raise site in their guarded
    5664region.
    5765The search includes handlers in the current function, as well as any in
     
    5967
    6068\paragraph{Matching}
    61 Each handler found has to be matched with the raised exception. The exception
    62 label defines a condition that is used with exception and decides if
     69Each handler found is matched with the raised exception. The exception
     70label defines a condition that is used with the exception and decides if
    6371there is a match or not.
    64 
    6572In languages where the first match is used, this step is intertwined with
    66 searching; a match check is preformed immediately after the search finds
    67 a possible handler.
     73searching; a match check is performed immediately after the search finds
     74a handler.
    6875
    6976\paragraph{Installing}
    70 After a handler is chosen it must be made ready to run.
     77After a handler is chosen, it must be made ready to run.
    7178The implementation can vary widely to fit with the rest of the
    7279design of the EHM. The installation step might be trivial or it could be
     
    7582
    7683If a matching handler is not guaranteed to be found, the EHM needs a
    77 different course of action for the case where no handler matches.
     84different course of action for this case.
    7885This situation only occurs with unchecked exceptions as checked exceptions
    79 (such as in Java) can make the guarantee.
    80 This unhandled action is usually very general, such as aborting the program.
     86(such as in Java) are guaranteed to find a matching handler.
     87The unhandled action is usually very general, such as aborting the program.
    8188
    8289\paragraph{Hierarchy}
     
    8592exception hierarchy is a natural extension of the object hierarchy.
    8693
    87 Consider the following hierarchy of exceptions:
     94Consider the following exception hierarchy:
    8895\begin{center}
    8996\input{exception-hierarchy}
    9097\end{center}
    91 
    9298A handler labeled with any given exception can handle exceptions of that
    9399type or any child type of that exception. The root of the exception hierarchy
    94 (here \code{C}{exception}) acts as a catch-all, leaf types catch single types
     100(here \code{C}{exception}) acts as a catch-all, leaf types catch single types,
    95101and the exceptions in the middle can be used to catch different groups of
    96102related exceptions.
    97103
    98104This system has some notable advantages, such as multiple levels of grouping,
    99 the ability for libraries to add new exception types and the isolation
     105the ability for libraries to add new exception types, and the isolation
    100106between different sub-hierarchies.
    101107This design is used in \CFA even though it is not a object-orientated
     
    110116is usually set up to do most of the work.
    111117
    112 The EHM can return control to many different places,
     118The EHM can return control to many different places, where
    113119the most common are after the handler definition (termination)
    114120and after the raise (resumption).
     
    117123For effective exception handling, additional information is often passed
    118124from the raise to the handler and back again.
    119 So far only communication of the exceptions' identity has been covered.
    120 A common communication method is putting fields into the exception instance
     125So far, only communication of the exception's identity is covered.
     126A common communication method for passing more information is putting fields into the exception instance
    121127and giving the handler access to them.
    122 Passing the exception by reference instead of by value can allow data to be
     128Using reference fields pointing to data at the raise location allows data to be
    123129passed in both directions.
    124130
    125131\section{Virtuals}
    126132Virtual types and casts are not part of \CFA's EHM nor are they required for
    127 any EHM.
    128 However, it is one of the best ways to support an exception hierarchy
     133an EHM.
     134However, one of the best ways to support an exception hierarchy
    129135is via a virtual hierarchy and dispatch system.
    130136
    131 Ideally, the virtual system would have been part of \CFA before the work
     137Ideally, the virtual system should have been part of \CFA before the work
    132138on exception handling began, but unfortunately it was not.
    133139Hence, only the features and framework needed for the EHM were
    134 designed and implemented. Other features were considered to ensure that
     140designed and implemented for this thesis. Other features were considered to ensure that
    135141the structure could accommodate other desirable features in the future
    136 but they were not implemented.
    137 The rest of this section will only discuss the implemented subset of the
    138 virtual system design.
     142but are not implemented.
     143The rest of this section only discusses the implemented subset of the
     144virtual-system design.
    139145
    140146The virtual system supports multiple ``trees" of types. Each tree is
     
    152158It is important to note that these are virtual members, not virtual methods
    153159of object-orientated programming, and can be of any type.
     160
     161\PAB{Need to look at these when done.
    154162
    155163\CFA still supports virtual methods as a special case of virtual members.
     
    165173as a hidden field.
    166174\todo{Might need a diagram for virtual structure.}
     175}%
    167176
    168177Up until this point the virtual system is similar to ones found in
    169 object-orientated languages but this where \CFA diverges. Objects encapsulate a
    170 single set of behaviours in each type, universally across the entire program,
    171 and indeed all programs that use that type definition. In this sense, the
    172 types are ``closed" and cannot be altered.
    173 
    174 In \CFA, types do not encapsulate any behaviour. Traits are local and
    175 types can begin to satisfy a trait, stop satisfying a trait or satisfy the same
    176 trait in a different way at any lexical location in the program.
    177 In this sense, they are ``open" as they can change at any time.
     178object-orientated languages but this is where \CFA diverges. Objects encapsulate a
     179single set of methods in each type, universally across the entire program,
     180and indeed all programs that use that type definition. Even if a type inherits and adds methods, it still encapsulate a
     181single set of methods. In this sense,
     182object-oriented types are ``closed" and cannot be altered.
     183
     184In \CFA, types do not encapsulate any code. Traits are local for each function and
     185types can satisfy a local trait, stop satisfying it or, satisfy the same
     186trait in a different way at any lexical location in the program where a function is call.
     187In this sense, the set of functions/variables that satisfy a trait for a type is ``open" as the set can change at every call site.
    178188This capability means it is impossible to pick a single set of functions
    179 that represent the type's implementation across the program.
     189that represent a type's implementation across a program.
    180190
    181191\CFA side-steps this issue by not having a single virtual table for each
    182192type. A user can define virtual tables that are filled in at their
    183193declaration and given a name. Anywhere that name is visible, even if it is
    184 defined locally inside a function (although that means it does not have a
    185 static lifetime), it can be used.
     194defined locally inside a function \PAB{What does this mean? (although that means it does not have a
     195static lifetime)}, it can be used.
    186196Specifically, a virtual type is ``bound" to a virtual table that
    187197sets the virtual members for that object. The virtual members can be accessed
     
    221231completing the virtual system). The imaginary assertions would probably come
    222232from a trait defined by the virtual system, and state that the exception type
    223 is a virtual type, is a descendant of @exception_t@ (the base exception type)
     233is a virtual type, is a descendant of @exception_t@ (the base exception type),
    224234and note its virtual table type.
    225235
     
    241251\end{cfa}
    242252Both traits ensure a pair of types are an exception type, its virtual table
    243 type
     253type,
    244254and defines one of the two default handlers. The default handlers are used
    245255as fallbacks and are discussed in detail in \vref{s:ExceptionHandling}.
     
    250260facing way. So these three macros are provided to wrap these traits to
    251261simplify referring to the names:
    252 @IS_EXCEPTION@, @IS_TERMINATION_EXCEPTION@ and @IS_RESUMPTION_EXCEPTION@.
     262@IS_EXCEPTION@, @IS_TERMINATION_EXCEPTION@, and @IS_RESUMPTION_EXCEPTION@.
    253263
    254264All three take one or two arguments. The first argument is the name of the
     
    272282\CFA provides two kinds of exception handling: termination and resumption.
    273283These twin operations are the core of \CFA's exception handling mechanism.
    274 This section will cover the general patterns shared by the two operations and
    275 then go on to cover the details each individual operation.
     284This section covers the general patterns shared by the two operations and
     285then goes on to cover the details of each individual operation.
    276286
    277287Both operations follow the same set of steps.
    278 Both start with the user preforming a raise on an exception.
    279 Then the exception propagates up the stack.
    280 If a handler is found the exception is caught and the handler is run.
     288First, a user raises an exception.
     289Second, the exception propagates up the stack.
     290Third, if a handler is found, the exception is caught and the handler is run.
    281291After that control continues at a raise-dependent location.
    282 If the search fails a default handler is run and, if it returns, then control
     292Fourth, if a handler is not found, a default handler is run and, if it returns, then control
    283293continues after the raise.
    284294
    285 This general description covers what the two kinds have in common.
    286 Differences include how propagation is preformed, where exception continues
    287 after an exception is caught and handled and which default handler is run.
     295%This general description covers what the two kinds have in common.
     296The differences in the two operations include how propagation is performed, where execution continues
     297after an exception is caught and handled, and which default handler is run.
    288298
    289299\subsection{Termination}
    290300\label{s:Termination}
    291 Termination handling is the familiar kind and used in most programming
     301Termination handling is the familiar EHM and used in most programming
    292302languages with exception handling.
    293303It is a dynamic, non-local goto. If the raised exception is matched and
     
    308318@is_termination_exception@ at the call site.
    309319Through \CFA's trait system, the trait functions are implicitly passed into the
    310 throw code and the EHM.
     320throw code for use by the EHM.
    311321A new @defaultTerminationHandler@ can be defined in any scope to
    312 change the throw's behaviour (see below).
     322change the throw's behaviour when a handler is not found (see below).
    313323
    314324The throw copies the provided exception into managed memory to ensure
     
    320330% How to say propagation starts, its first sub-step is the search.
    321331Then propagation starts with the search. \CFA uses a ``first match" rule so
    322 matching is preformed with the copied exception as the search continues.
    323 It starts from the throwing function and proceeds towards base of the stack,
     332matching is performed with the copied exception as the search key.
     333It starts from the raise in the throwing function and proceeds towards the base of the stack,
    324334from callee to caller.
    325 At each stack frame, a check is made for resumption handlers defined by the
     335At each stack frame, a check is made for termination handlers defined by the
    326336@catch@ clauses of a @try@ statement.
    327337\begin{cfa}
     
    335345\end{cfa}
    336346When viewed on its own, a try statement simply executes the statements
    337 in \snake{GUARDED_BLOCK} and when those are finished,
     347in the \snake{GUARDED_BLOCK}, and when those are finished,
    338348the try statement finishes.
    339349
     
    341351invoked functions, all the handlers in these statements are included in the
    342352search path.
    343 Hence, if a termination exception is raised these handlers may be matched
     353Hence, if a termination exception is raised, these handlers may be matched
    344354against the exception and may handle it.
    345355
    346356Exception matching checks the handler in each catch clause in the order
    347357they appear, top to bottom. If the representation of the raised exception type
    348 is the same or a descendant of @EXCEPTION_TYPE@$_i$ then @NAME@$_i$
     358is the same or a descendant of @EXCEPTION_TYPE@$_i$, then @NAME@$_i$
    349359(if provided) is
    350360bound to a pointer to the exception and the statements in @HANDLER_BLOCK@$_i$
     
    352362freed and control continues after the try statement.
    353363
    354 If no termination handler is found during the search then the default handler
    355 (\defaultTerminationHandler) visible at the raise statement is run.
    356 Through \CFA's trait system the best match at the raise statement will be used.
     364If no termination handler is found during the search, then the default handler
     365(\defaultTerminationHandler) visible at the raise statement is called.
     366Through \CFA's trait system the best match at the raise statement is used.
    357367This function is run and is passed the copied exception.
    358 If the default handler is run control continues after the raise statement.
     368If the default handler finishes, control continues after the raise statement.
    359369
    360370There is a global @defaultTerminationHandler@ that is polymorphic over all
    361371termination exception types.
    362 Since it is so general a more specific handler can be
    363 defined and is used for those types, effectively overriding the handler
    364 for a particular exception type.
    365372The global default termination handler performs a cancellation
    366 (see \vref{s:Cancellation}) on the current stack with the copied exception.
     373(see \vref{s:Cancellation} for the justification) on the current stack with the copied exception.
     374Since it is so general, a more specific handler is usually
     375defined, possibly with a detailed message, and used for specific exception type, effectively overriding the default handler.
    367376
    368377\subsection{Resumption}
    369378\label{s:Resumption}
    370379
    371 Resumption exception handling is less common than termination but is
     380Resumption exception handling is the less familar EHM, but is
    372381just as old~\cite{Goodenough75} and is simpler in many ways.
    373382It is a dynamic, non-local function call. If the raised exception is
    374 matched a closure is taken from up the stack and executed,
     383matched, a closure is taken from up the stack and executed,
    375384after which the raising function continues executing.
    376385The common uses for resumption exceptions include
     
    378387function once the error is corrected, and
    379388ignorable events, such as logging where nothing needs to happen and control
    380 should always continue from the same place.
     389should always continue from the raise point.
    381390
    382391A resumption raise is started with the @throwResume@ statement:
     
    392401the exception system while handling the exception.
    393402
    394 At run-time, no exception copy is made.
    395 Resumption does not unwind the stack nor otherwise remove values from the
    396 current scope, so there is no need to manage memory to keep things in scope.
    397 
    398 The EHM then begins propagation. The search starts from the raise in the
     403At run-time, no exception copy is made, since
     404resumption does not unwind the stack nor otherwise remove values from the
     405current scope, so there is no need to manage memory to keep the exception in scope.
     406
     407Then propagation starts with the search. It starts from the raise in the
    399408resuming function and proceeds towards the base of the stack,
    400409from callee to caller.
     
    410419}
    411420\end{cfa}
     421% PAB, you say this above.
     422% When a try statement is executed, it simply executes the statements in the
     423% @GUARDED_BLOCK@ and then finishes.
     424%
     425% However, while the guarded statements are being executed, including any
     426% invoked functions, all the handlers in these statements are included in the
     427% search path.
     428% Hence, if a resumption exception is raised, these handlers may be matched
     429% against the exception and may handle it.
     430%
     431% Exception matching checks the handler in each catch clause in the order
     432% they appear, top to bottom. If the representation of the raised exception type
     433% is the same or a descendant of @EXCEPTION_TYPE@$_i$, then @NAME@$_i$
     434% (if provided) is bound to a pointer to the exception and the statements in
     435% @HANDLER_BLOCK@$_i$ are executed.
     436% If control reaches the end of the handler, execution continues after the
     437% the raise statement that raised the handled exception.
     438%
     439% Like termination, if no resumption handler is found during the search,
     440% then the default handler (\defaultResumptionHandler) visible at the raise
     441% statement is called. It will use the best match at the raise sight according
     442% to \CFA's overloading rules. The default handler is
     443% passed the exception given to the raise. When the default handler finishes
     444% execution continues after the raise statement.
     445%
     446% There is a global @defaultResumptionHandler{} is polymorphic over all
     447% resumption exceptions and performs a termination throw on the exception.
     448% The \defaultTerminationHandler{} can be overridden by providing a new
     449% function that is a better match.
     450
     451The @GUARDED_BLOCK@ and its associated nested guarded statements work the same
     452for resumption as for termination, as does exception matching at each
     453@catchResume@. Similarly, if no resumption handler is found during the search,
     454then the currently visible default handler (\defaultResumptionHandler) is
     455called and control continues after the raise statement if it returns. Finally,
     456there is also a global @defaultResumptionHandler@, which can be overridden,
     457that is polymorphic over all resumption exceptions but performs a termination
     458throw on the exception rather than a cancellation.
     459
     460Throwing the exception in @defaultResumptionHandler@ has the positive effect of
     461walking the stack a second time for a recovery handler. Hence, a programmer has
     462two chances for help with a problem, fixup or recovery, should either kind of
     463handler appear on the stack. However, this dual stack walk leads to following
     464apparent anomaly:
     465\begin{cfa}
     466try {
     467        throwResume E;
     468} catch (E) {
     469        // this handler runs
     470}
     471\end{cfa}
     472because the @catch@ appears to handle a @throwResume@, but a @throwResume@ only
     473matches with @catchResume@. The anomaly results because the unmatched
     474@catchResuem@, calls @defaultResumptionHandler@, which in turn throws @E@.
     475
    412476% I wonder if there would be some good central place for this.
    413 Note that termination handlers and resumption handlers may be used together
     477Note, termination and resumption handlers may be used together
    414478in a single try statement, intermixing @catch@ and @catchResume@ freely.
    415479Each type of handler only interacts with exceptions from the matching
    416480kind of raise.
    417 When a try statement is executed, it simply executes the statements in the
    418 @GUARDED_BLOCK@ and then finishes.
    419 
    420 However, while the guarded statements are being executed, including any
    421 invoked functions, all the handlers in these statements are included in the
    422 search path.
    423 Hence, if a resumption exception is raised these handlers may be matched
    424 against the exception and may handle it.
    425 
    426 Exception matching checks the handler in each catch clause in the order
    427 they appear, top to bottom. If the representation of the raised exception type
    428 is the same or a descendant of @EXCEPTION_TYPE@$_i$ then @NAME@$_i$
    429 (if provided) is bound to a pointer to the exception and the statements in
    430 @HANDLER_BLOCK@$_i$ are executed.
    431 If control reaches the end of the handler, execution continues after the
    432 the raise statement that raised the handled exception.
    433 
    434 Like termination, if no resumption handler is found during the search,
    435 the default handler (\defaultResumptionHandler) visible at the raise
    436 statement is called. It will use the best match at the raise sight according
    437 to \CFA's overloading rules. The default handler is
    438 passed the exception given to the raise. When the default handler finishes
    439 execution continues after the raise statement.
    440 
    441 There is a global \defaultResumptionHandler{} is polymorphic over all
    442 resumption exceptions and preforms a termination throw on the exception.
    443 The \defaultTerminationHandler{} can be overridden by providing a new
    444 function that is a better match.
    445481
    446482\subsubsection{Resumption Marking}
    447483\label{s:ResumptionMarking}
    448484A key difference between resumption and termination is that resumption does
    449 not unwind the stack. A side effect that is that when a handler is matched
    450 and run it's try block (the guarded statements) and every try statement
     485not unwind the stack. A side effect is that, when a handler is matched
     486and run, its try block (the guarded statements) and every try statement
    451487searched before it are still on the stack. There presence can lead to
    452 the recursive resumption problem.
     488the \emph{recursive resumption problem}.
    453489
    454490The recursive resumption problem is any situation where a resumption handler
     
    464500When this code is executed, the guarded @throwResume@ starts a
    465501search and matches the handler in the @catchResume@ clause. This
    466 call is placed on the stack above the try-block. The second raise then
    467 searches the same try block and puts another instance of the
     502call is placed on the stack above the try-block. Now the second raise in the handler
     503searches the same try block, matches, and puts another instance of the
    468504same handler on the stack leading to infinite recursion.
    469505
    470 While this situation is trivial and easy to avoid, much more complex cycles
    471 can form with multiple handlers and different exception types.
    472 
    473 To prevent all of these cases, a each try statement is ``marked" from the
    474 time the exception search reaches it to either when the exception is being
    475 handled completes the matching handler or when the search reaches the base
     506While this situation is trivial and easy to avoid, much more complex cycles can
     507form with multiple handlers and different exception types.  The key point is
     508that the programmer's intuition expects every raise in a handler to start
     509searching \emph{below} the @try@ statement, making it difficult to understand
     510and fix the problem.
     511
     512To prevent all of these cases, each try statement is ``marked" from the
     513time the exception search reaches it to either when a matching handler
     514completes or when the search reaches the base
    476515of the stack.
    477516While a try statement is marked, its handlers are never matched, effectively
     
    485524for instance, marking just the handlers that caught the exception,
    486525would also prevent recursive resumption.
    487 However, these rules mirror what happens with termination.
    488 
    489 The try statements that are marked are the ones that would be removed from
    490 the stack if this was a termination exception, that is those on the stack
     526However, the rule selected mirrors what happens with termination,
     527and hence, matches programmer intuition that a raise searches below a try.
     528
     529In detail, the marked try statements are the ones that would be removed from
     530the stack for a termination exception, \ie those on the stack
    491531between the handler and the raise statement.
    492532This symmetry applies to the default handler as well, as both kinds of
     
    522562        // Only handle IO failure for f3.
    523563}
    524 // Can't handle a failure relating to f2 here.
     564// Handle a failure relating to f2 further down the stack.
    525565\end{cfa}
    526566In this example the file that experienced the IO error is used to decide
     
    553593
    554594\subsection{Comparison with Reraising}
    555 A more popular way to allow handlers to match in more detail is to reraise
    556 the exception after it has been caught, if it could not be handled here.
    557 On the surface these two features seem interchangeable.
    558 
    559 If @throw;@ (no argument) starts a termination reraise,
    560 which is the same as a raise but reuses the last caught exception,
    561 then these two statements have the same behaviour:
    562 \begin{cfa}
    563 try {
    564     do_work_may_throw();
    565 } catch(exception_t * exc ; can_handle(exc)) {
    566     handle(exc);
    567 }
    568 \end{cfa}
    569 
    570 \begin{cfa}
    571 try {
    572     do_work_may_throw();
    573 } catch(exception_t * exc) {
    574     if (can_handle(exc)) {
    575         handle(exc);
    576     } else {
    577         throw;
    578     }
    579 }
    580 \end{cfa}
    581 That is, they will have the same behaviour in isolation.
     595Without conditional catch, the only approach to match in more detail is to reraise
     596the exception after it has been caught, if it could not be handled.
     597\begin{center}
     598\begin{tabular}{l|l}
     599\begin{cfa}
     600try {
     601        do_work_may_throw();
     602} catch(excep_t * ex; can_handle(ex)) {
     603
     604        handle(ex);
     605
     606
     607
     608}
     609\end{cfa}
     610&
     611\begin{cfa}
     612try {
     613        do_work_may_throw();
     614} catch(excep_t * ex) {
     615        if (can_handle(ex)) {
     616                handle(ex);
     617        } else {
     618                throw;
     619        }
     620}
     621\end{cfa}
     622\end{tabular}
     623\end{center}
     624Notice catch-and-reraise increases complexity by adding additional data and
     625code to the exception process. Nevertheless, catch-and-reraise can simulate
     626conditional catch straightforwardly, when exceptions are disjoint, \ie no
     627inheritance.
     628
     629However, catch-and-reraise simulation becomes unusable for exception inheritance.
     630\begin{flushleft}
     631\begin{cfa}[xleftmargin=6pt]
     632exception E1;
     633exception E2(E1); // inheritance
     634\end{cfa}
     635\begin{tabular}{l|l}
     636\begin{cfa}
     637try {
     638        ... foo(); ... // raise E1/E2
     639        ... bar(); ... // raise E1/E2
     640} catch( E2 e; e.rtn == foo ) {
     641        ...
     642} catch( E1 e; e.rtn == foo ) {
     643        ...
     644} catch( E1 e; e.rtn == bar ) {
     645        ...
     646}
     647
     648\end{cfa}
     649&
     650\begin{cfa}
     651try {
     652        ... foo(); ...
     653        ... bar(); ...
     654} catch( E2 e ) {
     655        if ( e.rtn == foo ) { ...
     656        } else throw; // reraise
     657} catch( E1 e ) {
     658        if (e.rtn == foo) { ...
     659        } else if (e.rtn == bar) { ...
     660        else throw; // reraise
     661}
     662\end{cfa}
     663\end{tabular}
     664\end{flushleft}
     665The derived exception @E2@ must be ordered first in the catch list, otherwise
     666the base exception @E1@ catches both exceptions. In the catch-and-reraise code
     667(right), the @E2@ handler catches exceptions from both @foo@ and
     668@bar@. However, the reraise misses the following catch clause. To fix this
     669problem, an enclosing @try@ statement is need to catch @E2@ for @bar@ from the
     670reraise, and its handler must duplicate the inner handler code for @bar@. To
     671generalize, this fix for any amount of inheritance and complexity of try
     672statement requires a technique called \emph{try-block
     673splitting}~\cite{Krischer02}, which is not discussed in this thesis. It is
     674sufficient to state that conditional catch is more expressive than
     675catch-and-reraise in terms of complexity.
     676
     677\begin{comment}
     678That is, they have the same behaviour in isolation.
    582679Two things can expose differences between these cases.
    583680
    584681One is the existence of multiple handlers on a single try statement.
    585 A reraise skips all later handlers on this try statement but a conditional
     682A reraise skips all later handlers for a try statement but a conditional
    586683catch does not.
    587 Hence, if an earlier handler contains a reraise later handlers are
    588 implicitly skipped, with a conditional catch they are not.
     684% Hence, if an earlier handler contains a reraise later handlers are
     685% implicitly skipped, with a conditional catch they are not.
    589686Still, they are equivalently powerful,
    590687both can be used two mimic the behaviour of the other,
     
    637734%   `exception_ptr current_exception() noexcept;`
    638735% https://www.python.org/dev/peps/pep-0343/
     736\end{comment}
    639737
    640738\section{Finally Clauses}
     
    652750The @FINALLY_BLOCK@ is executed when the try statement is removed from the
    653751stack, including when the @GUARDED_BLOCK@ finishes, any termination handler
    654 finishes or during an unwind.
     752finishes, or during an unwind.
    655753The only time the block is not executed is if the program is exited before
    656754the stack is unwound.
     
    668766
    669767Not all languages with unwinding have finally clauses. Notably \Cpp does
    670 without it as descructors, and the RAII design pattern, serve a similar role.
    671 Although destructors and finally clauses can be used in the same cases,
     768without it as destructors, and the RAII design pattern, serve a similar role.
     769Although destructors and finally clauses can be used for the same cases,
    672770they have their own strengths, similar to top-level function and lambda
    673771functions with closures.
    674 Destructors take more work for their first use, but if there is clean-up code
    675 that needs to be run every time a type is used they soon become much easier
     772Destructors take more work for their creation, but if there is clean-up code
     773that needs to be run every time a type is used, they are much easier
    676774to set-up.
    677775On the other hand finally clauses capture the local context, so is easy to
    678776use when the clean-up is not dependent on the type of a variable or requires
    679777information from multiple variables.
    680 % To Peter: I think these are the main points you were going for.
    681778
    682779\section{Cancellation}
     
    691788raise, this exception is not used in matching only to pass information about
    692789the cause of the cancellation.
    693 (This also means matching cannot fail so there is no default handler.)
     790Finaly, since a cancellation only unwinds and forwards, there is no default handler.
    694791
    695792After @cancel_stack@ is called the exception is copied into the EHM's memory
     
    702799After the main stack is unwound there is a program-level abort.
    703800
    704 There are two reasons for these semantics.
    705 The first is that it had to do this abort.
    706 in a sequential program as there is nothing else to notify and the simplicity
    707 of keeping the same behaviour in sequential and concurrent programs is good.
     801The reasons for this semantics in a sequential program is that there is no more code to execute.
     802This semantics also applies to concurrent programs, too, even if threads are running.
     803That is, if any threads starts a cancellation, it implies all threads terminate.
     804Keeping the same behaviour in sequential and concurrent programs is simple.
    708805Also, even in concurrent programs there may not currently be any other stacks
    709806and even if other stacks do exist, main has no way to know where they are.
     
    750847caller's context and passes it to the internal report.
    751848
    752 A coroutine knows of two other coroutines, its starter and its last resumer.
     849A coroutine only knows of two other coroutines, its starter and its last resumer.
    753850The starter has a much more distant connection, while the last resumer just
    754851(in terms of coroutine state) called resume on this coroutine, so the message
     
    758855cascade an error across any number of coroutines, cleaning up each in turn,
    759856until the error is handled or a thread stack is reached.
     857
     858\PAB{Part of this I do not understand. A cancellation cannot be caught. But you
     859talk about handling a cancellation in the last sentence. Which is correct?}
  • doc/theses/andrew_beach_MMath/uw-ethesis.tex

    r478c610 r9373b6a  
    247247\input{performance}
    248248\input{future}
     249\input{conclusion}
    249250
    250251%----------------------------------------------------------------------
  • tests/io/manipulatorsOutput3.cfa

    r478c610 r9373b6a  
    11//
    22// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
    3 //
     3//
     4// The contents of this file are covered under the licence agreement in the
     5// file "LICENCE" distributed with Cforall.
     6//
    47// manipulatorsOutput3.cfa --
    58//
     
    710// Created On       : Tue Apr 13 17:54:23 2021
    811// Last Modified By : Peter A. Buhr
    9 // Last Modified On : Tue Apr 13 17:54:48 2021
    10 // Update Count     : 1
     12// Last Modified On : Sun Aug  8 22:37:20 2021
     13// Update Count     : 2
    1114//
    1215
  • tests/sum.cfa

    r478c610 r9373b6a  
    1111// Created On       : Wed May 27 17:56:53 2015
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Tue Jul 16 09:51:37 2019
    14 // Update Count     : 336
     13// Last Modified On : Thu Aug  5 21:27:25 2021
     14// Update Count     : 346
    1515//
    1616
     
    2020trait sumable( T ) {
    2121        void ?{}( T &, zero_t );                                                        // 0 literal constructor
     22        void ?{}( T &, one_t );                                                         // 1 literal constructor
    2223        T ?+?( T, T );                                                                          // assortment of additions
    23         T ?+=?( T &, T );
    24         T ++?( T & );
    25         T ?++( T & );
     24        T ?+=?( T &, T );                                                                       // get pre/post ++ with += and one_t
    2625}; // sumable
    2726
    28 forall( T | sumable( T ) )                                              // use trait
     27forall( T | sumable( T ) )                                                              // use trait
    2928T sum( size_t size, T a[] ) {
    3029        T total = 0;                                                                            // initialize by 0 constructor
     
    3534
    3635int main( void ) {
    37 #if 0
    3836        const int low = 5, High = 15, size = High - low;
    3937
     
    9492        S ?+?( S t1, S t2 ) { return (S){ t1.i + t2.i, t1.j + t2.j }; }
    9593        S ?+=?( S & t1, S t2 ) { t1 = t1 + t2; return t1; }
    96         S ++?( S & t ) { t += (S){1}; return t; }
    97         S ?++( S & t ) { S temp = t; t += (S){1}; return temp; }
    9894        ofstream & ?|?( ofstream & os, S v ) { return os | v.i | v.j; }
    9995        void ?|?( ofstream & os, S v ) { (ofstream &)(os | v); ends( os ); }
    10096
    101         S s = (S){0}, a[size], v = { low, low };
     97        S s = 0, a[size], v = { low, low };
    10298        for ( int i = 0; i < size; i += 1, v += (S){1} ) {
    10399                s += (S)v;
     
    122118                 | sum( size, gs.x ) | ", check" | (int)s;              // add field array in generic type
    123119        delete( gs.x );
    124 #else
    125         const int low = 5, High = 15, size = High - low;
    126 
    127         signed char s = 0, a[size], v = (char)low;
    128         for ( int i = 0; i < size; i += 1, v += 1hh ) {
    129                 s += v;
    130                 a[i] = v;
    131         } // for
    132         printf( "sum from %d to %d is %hhd, check %hhd\n", low, High,
    133                  sum( size, (signed char *)a ), (signed char)s );
    134 
    135         unsigned char s = 0, a[size], v = low;
    136         for ( int i = 0; i < size; i += 1, v += 1hhu ) {
    137                 s += (unsigned char)v;
    138                 a[i] = (unsigned char)v;
    139         } // for
    140         printf( "sum from %d to %d is %hhu, check %hhu\n", low, High,
    141                  sum( size, (unsigned char *)a ), (unsigned char)s );
    142 
    143         short int s = 0, a[size], v = low;
    144         for ( int i = 0; i < size; i += 1, v += 1h ) {
    145                 s += (short int)v;
    146                 a[i] = (short int)v;
    147         } // for
    148         printf( "sum from %d to %d is %hd, check %hd\n", low, High,
    149                  sum( size, (short int *)a ), (short int)s );
    150 
    151         int s = 0, a[size], v = low;
    152         for ( int i = 0; i < size; i += 1, v += 1 ) {
    153                 s += (int)v;
    154                 a[i] = (int)v;
    155         } // for
    156         printf( "sum from %d to %d is %d, check %d\n", low, High,
    157                  sum( size, (int *)a ), (int)s );
    158 
    159         float s = 0.0f, a[size], v = low / 10.0f;
    160         for ( int i = 0; i < size; i += 1, v += 0.1f ) {
    161                 s += (float)v;
    162                 a[i] = (float)v;
    163         } // for
    164         printf( "sum from %g to %g is %g, check %g\n", low / 10.0f, High / 10.0f,
    165                  sum( size, (float *)a ), (float)s );
    166 
    167         double s = 0.0, a[size], v = low / 10.0;
    168         for ( int i = 0; i < size; i += 1, v += 0.1 ) {
    169                 s += (double)v;
    170                 a[i] = (double)v;
    171         } // for
    172         printf( "sum from %g to %g is %g, check %g\n", low / 10.0f, High / 10.0f,
    173                  sum( size, (double *)a ), (double)s );
    174 
    175         struct S { int i, j; };
    176         void ?{}( S & s ) { s.[i, j] = 0; }
    177         void ?{}( S & s, int i ) { s.[i, j] = [i, 0]; }
    178         void ?{}( S & s, int i, int j ) { s.[i, j] = [i, j]; }
    179         void ?{}( S & s, zero_t ) { s.[i, j] = 0; }
    180         void ?{}( S & s, one_t ) { s.[i, j] = 1; }
    181         S ?+?( S t1, S t2 ) { return (S){ t1.i + t2.i, t1.j + t2.j }; }
    182         S ?+=?( S & t1, S t2 ) { t1 = t1 + t2; return t1; }
    183         S ++?( S & t ) { t += (S){1}; return t; }
    184         S ?++( S & t ) { S temp = t; t += (S){1}; return temp; }
    185         ofstream & ?|?( ofstream & os, S v ) { return os | v.i | v.j; }
    186         void ?|?( ofstream & os, S v ) { (ofstream &)(os | v); ends( os ); }
    187 
    188         S s = 0, a[size], v = { low, low };
    189         for ( int i = 0; i < size; i += 1, v += (S){1} ) {
    190                 s += (S)v;
    191                 a[i] = (S)v;
    192         } // for
    193         printf( "sum from %d to %d is %d %d, check %d %d\n", low, High,
    194                  sum( size, (S *)a ).[i, j], s.[i, j] );
    195 
    196         forall( Impl | sumable( Impl ) )
    197         struct GS {
    198                 Impl * x, * y;
    199         };
    200         GS(int) gs;
    201         // FIX ME, resolution problem with anew not picking up the LH type
    202         gs.x = (typeof(gs.x))anew( size );                                      // create array storage for field
    203         s = 0; v = low;
    204         for ( int i = 0; i < size; i += 1, v += 1 ) {
    205                 s += (int)v;
    206                 gs.x[i] = (int)v;                                                               // set field array in generic type
    207         } // for
    208         printf( "sum from %d to %d is %d, check %d\n", low, High,
    209                  sum( size, gs.x ), (int)s );           // add field array in generic type
    210         delete( gs.x );
    211 #endif
    212120} // main
    213121
Note: See TracChangeset for help on using the changeset viewer.