Difference between revisions of "Exceptions as Objects"

 
 
(23 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
[[Category:Exception]]
 
[[Category:Exception]]
 +
[[Category:Eiffel Language]]
 
== Overview ==
 
== Overview ==
 
This article describes many aspects of Exceptions as Objects (ECMA-367 8.26) which will be implemented in ISE Eiffel. All exceptions will be raised as objects which can be accessed by `last_exception'. Exceptions as objects are known as type EXCEPTION and its descendants. EXCEPTION_MANAGER is introduced to handle common exception class operations, i.e. catch, and ignore.
 
This article describes many aspects of Exceptions as Objects (ECMA-367 8.26) which will be implemented in ISE Eiffel. All exceptions will be raised as objects which can be accessed by `last_exception'. Exceptions as objects are known as type EXCEPTION and its descendants. EXCEPTION_MANAGER is introduced to handle common exception class operations, i.e. catch, and ignore.
 +
 +
This doc is from the original working version: http://docs.google.com/Doc?docid=dckspcv8_9htpfm4&hl=en
  
 
== Exception class hierarchy ==
 
== Exception class hierarchy ==
   EXCEPTION
+
   {{Red|EXCEPTION}}
     SYSTEM_EXCEPTION
+
     {{Red|SYSTEM_EXCEPTION}}
         MACHINE_EXCEPTION
+
         {{Red|MACHINE_EXCEPTION}}
           OPERATING_SYSTEM_EXCEPTION
+
           {{Red|OPERATING_SYSTEM_EXCEPTION}}
               COM_FAILURE
+
               {{Red|COM_FAILURE}}
               OPERATING_SYSTEM_FAILURE
+
               {{Red|OPERATING_SYSTEM_FAILURE}}
               OPERATING_SYSTEM_SIGNAL_FAILURE
+
               {{Red|OPERATING_SYSTEM_SIGNAL_FAILURE}}
           HARDWARE_EXCEPTION
+
           {{Red|HARDWARE_EXCEPTION}}
               FLOATING_POINT_FAILURE
+
               {{Red|FLOATING_POINT_FAILURE}}
          EIFFEL_EXCEPTION
+
        {{Red|EIFFEL_EXCEPTION}}
           LANGUAGE_EXCEPTION
+
           {{Red|LANGUAGE_EXCEPTION}}
               BAD_INSPECT_VALUE
+
               {{Red|BAD_INSPECT_VALUE}}
               VOID_TARGET
+
               {{Red|VOID_TARGET}}
               VOID_ASSIGNED_TO_EXPANDED
+
               {{Red|VOID_ASSIGNED_TO_EXPANDED}}
                ROUTINE_FAILURE
+
              {{Red|ROUTINE_FAILURE}}
                EIFFELSTUDIO_SPECIFIC_LANGUAGE_EXCEPTION
+
              EIFFELSTUDIO_SPECIFIC_LANGUAGE_EXCEPTION
                    CREATE_ON_DEFERRED
+
                CREATE_ON_DEFERRED
                    DOLLAR_APPLIED_TO_MELTED_FEATURE    REMOVE ?  IF NOT, CHANGE NAME (USE E.G. "ADDRESS" INST. OF "DOLLAR"
+
                ADDRESS_APPLIED_TO_MELTED_FEATURE
           EIFFEL_RUNTIME_EXCEPTION
+
           {{Red|EIFFEL_RUNTIME_EXCEPTION}}
 
               NO_MORE_MEMORY
 
               NO_MORE_MEMORY
 
               DATA_EXCEPTION
 
               DATA_EXCEPTION
Line 28: Line 31:
 
                 SERIALIZATION_FAILURE
 
                 SERIALIZATION_FAILURE
 
                 MISMATCH_FAILURE
 
                 MISMATCH_FAILURE
                EXTERNAL_FAILURE-- Only used for threads at the moment
+
              EXTERNAL_FAILURE-- Only used for threads at the moment
                EIFFEL_RUNTIME_PANIC               
+
              EIFFEL_RUNTIME_PANIC               
     ASSERTION_VIOLATION
+
     {{Red|ASSERTION_VIOLATION}}
       INVARIANT_VIOLATION
+
       {{Red|INVARIANT_VIOLATION}}
       PRECONDITION_VIOLATION
+
       {{Red|PRECONDITION_VIOLATION}}
       POSTCONDITION_VIOLATION
+
       {{Red|POSTCONDITION_VIOLATION}}
       CHECK_VIOLATION
+
       {{Red|CHECK_VIOLATION}}
       VARIANT_VIOLATION
+
       {{Red|VARIANT_VIOLATION}}
       OLD_VIOLATION
+
       {{Red|OLD_VIOLATION}}
       LOOP_INVARIANT_VIOLATION
+
       {{Red|LOOP_INVARIANT_VIOLATION}}
     DEVELOPER_EXCEPTION
+
     {{Red|DEVELOPER_EXCEPTION}}
     OBSOLETE EXCEPTION       
+
     {{Red|OBSOLETE_EXCEPTION}}   
 
       RESUMPTION_FAILURE Was RESUMPTION_FAILED.
 
       RESUMPTION_FAILURE Was RESUMPTION_FAILED.
 
       RESCUE_FAILURE --------- SHOULD NOT APPLY ANY MORE WITH ISO/ECMA, CHECK!!!
 
       RESCUE_FAILURE --------- SHOULD NOT APPLY ANY MORE WITH ISO/ECMA, CHECK!!!
 
       EXCEPTION_IN_SIGNAL_HANDLER_FAILURE
 
       EXCEPTION_IN_SIGNAL_HANDLER_FAILURE
  
These classes plus EXCEPTION_MANAGER will be place at base\elks\kernel\exceptions\.
+
Classes in red plus EXCEPTION_MANAGER will be placed at base\elks\kernel\exceptions\.
 
+
The rests are ise specific.
 +
<br>
 
'''Terminology'''
 
'''Terminology'''
  we use _EXCEPTION for intermediate nodes in the hierarchy; when we need a term in the leaves of the hierarchy we don't use EXCEPTION but
+
We use _EXCEPTION for intermediate nodes in the hierarchy; when we need a term in the leaves of the hierarchy we don't use EXCEPTION but
 
    
 
    
     * _VIOLATION for assertions
+
     * _VIOLATION for assertions (also used for ASSERTION_VIOLATION, an intermediate node)
 
     * _FAILURE otherwise
 
     * _FAILURE otherwise
 
    
 
    
   This is consistent with Eiffel exception terminology since from the viewpoint of Eiffel these things have failed, for example a signal was not handled properly.  
+
   This is consistent with Eiffel exception terminology since from the viewpoint of Eiffel these things have failed, for example a signal was not handled properly. The Eiffel runtime is causing an exception in the Eiffel code as a result, but the original event was a failure.  Hence SERIALIZATION_FAILURE etc.
  The Eiffel runtime is causing an exception in the Eiffel code as a result, but the original event was a failure.  Hence SERIALIZATION_FAILURE etc.
+
 
 +
== Raise and catch an exception ==
 +
 
 +
==== Catching an exception ====
 +
All exceptions can possibly be caught. `is_caught' is set by default. Only the given type of exception is `ignore'd in EXCEPTION_MANAGER if possible, it hence is not caught.
 +
The caught exception can be accessed by `last_exception'.
 +
 
 +
==== Raising an exception ====
 +
There are two types of exceptions concerning how an exception is raised.
 +
* System raised
 +
Exception raised through the runtime. Most exceptions of this type are predefine as classes in base library. i.e. assertion violations, no memory exceptions and routine failures.
 +
* User raised
 +
User raised exceptions are initialized by users and raised by explicit call of {EXCEPTION}.raise.
 +
 
 +
Theoretically the runtime can raise any exceptions known. A user can only raise an EXCEPTION that is `is_raisable'. `is_raisable' is possible true only when the exception is of DEVELOPER_EXCEPTION. This means only raising a DEVELOPER_EXCEPTION or its descendant is guaranteed correct.
  
 
== Ignoring, continuing an exception ==
 
== Ignoring, continuing an exception ==
Line 62: Line 80:
 
   * Ignored: lead to no change of non-exception semantics.
 
   * Ignored: lead to no change of non-exception semantics.
 
   * Continued: lead to execution of a programmer-specified routine, then to continuation of the execution according to non-exception semantics.
 
   * Continued: lead to execution of a programmer-specified routine, then to continuation of the execution according to non-exception semantics.
 +
 +
An ignorable exception can be ignored. When an exception is ignored, the raising does nothing as if non-exception semantics.
 +
What are the exceptions not ignorable?
  
 
Related queries in EXCEPTION:
 
Related queries in EXCEPTION:
  is_ignored: BOOLEAN
+
 
  is_caught: BOOLEAN
+
<eiffel>
  is_ignorable: BOOLEAN
+
is_ignored: BOOLEAN
 +
is_caught: BOOLEAN
 +
is_ignorable: BOOLEAN
 +
</eiffel>
  
 
Related routines in EXCEPTION_MANAGER:
 
Related routines in EXCEPTION_MANAGER:
  is_caught (a_exception: TYPE [EXCEPTION]): BOOLEAN
+
 
  is_ignored (a_exception: TYPE [EXCEPTION]): BOOLEAN
+
<eiffel>
  catch (a_exception: TYPE [EXCEPTION])  
+
is_caught (a_exception: TYPE [EXCEPTION]): BOOLEAN
  ignore (a_exception: TYPE [EXCEPTION])  
+
is_ignored (a_exception: TYPE [EXCEPTION]): BOOLEAN
  set_is_ignored (a_exception: TYPE [EXCEPTION]; a_ignored: BOOLEAN)
+
is_ignorable (a_exception: TYPE [EXCEPTION]): BOOLEAN
 +
catch (a_exception: TYPE [EXCEPTION])  
 +
ignore (a_exception: TYPE [EXCEPTION])  
 +
set_is_ignored (a_exception: TYPE [EXCEPTION]; a_ignored: BOOLEAN)
 +
</eiffel>
 +
 
 +
== `origin' VS `cause' ==
 +
 
 +
* The origin of an exception is, among all exceptions that have so far been triggered but not handled, the most recent one that is not a ROUTINE_FAILURE. Because a ROUTINE_FAILURE is always the result of an exception of another kind, the `origin' is always defined.
 +
 
 +
* The `cause' of an exception is only interesting in the case of an exception triggered in a rescue clause. In that case the exception is the result of incomplete handling of another exception (which might be a ROUTINE_FAILURE or any other kind). Then the `cause' is that other exception.
 +
 
 +
* If an exception was not triggered in a rescue clause, its `cause' is the exception itself.
 +
 
 +
== Exception at rescue clause ==
 +
See the following diagram:
 +
 
 +
[[Image:exception_in_rescue.png]]
 +
 
 +
Exception e2 is kept as `cause' at d.f4 in which e3 is raised, and being called in rescue clause r2. In this case e3 is accessible by `last_exception' and e2 is accessible by `cause' of e3.
 +
<br>
 +
<br>
 +
<b>
 +
A behavior should be clarified, that when an exception occurs deep in execution level of a rescue clause, `last_exception' is understood as "last unhandled exception".
 +
</b>
 +
<br>
 +
1. A new exception causes "last_exception" to be saved somewhere before
 +
entering "rescue" clause. After that the new exception object is attached to
 +
"last_exception".
 +
 
 +
2. If an exception is not handled (there is no rescue clause or "retry" is not
 +
performed), a new exception object "ROUTINE_FAILURE" is created, its attribute
 +
"original_exception" is set to "last_exception", and "last_exception" is set to
 +
this new "ROUTINE_FAILURE" object.
 +
 
 +
3. If an exception is handled ("retry" is executed), "last_exception" is attached
 +
a value saved in step 1.
 +
 
 +
Example:
 +
If "last_exception" in the following code snippet is modified
 +
by the call to feature "h" that raises an exception internally and handles it?
 +
<eiffel>
 +
        rescue
 +
                -- "last_exception" is set to "X".
 +
                -- Call feature that raises exception "Y", but handles it.
 +
            h
 +
 
 +
                -- Is "last_exception" set to "X" or to "Y"?
 +
                -- The answer is X.
 +
</eiffel>
 +
 
 +
== OLD_VIOLATION ==
 +
 
 +
OLD_VIOLATION behaves similarly with ROUTINE_FAILURE. In other words, OLD_VIOLATION is never a "root" exception of an exception chain. According to ECMA 8.26.11, OLD_VIOLATION should be treated as a "root" exception. But I believe it is more interesting to know the cause (original exception) of the old voilation. This will be clarified soon.
 +
 
 +
== Class ANY ==
 +
This is now done in EXCEPTION_MANAGER.
 +
<eiffel>
 +
class ANY
 +
...
 +
feature -- Exception
 +
 
 +
    frozen last_exception: EXCEPTION
 +
            -- Last exception
 +
        external
 +
            "built_in"
 +
        end
 +
...
 +
</eiffel>
  
 
== Class EXCEPTION ==
 
== Class EXCEPTION ==
Line 85: Line 177:
 
-- Code of the exception.
 
-- Code of the exception.
 
-- |Maybe we don't need this anymore
 
-- |Maybe we don't need this anymore
 
data: ANY
 
-- Data set by user
 
  
 
exception_trace: STRING_8
 
exception_trace: STRING_8
Line 100: Line 189:
 
original: EXCEPTION
 
original: EXCEPTION
 
-- Original exception that triggered current exception
 
-- Original exception that triggered current exception
 +
 +
cause: EXCEPTION
 +
-- Unhandled exception before current exception was triggered in a rescue clause
  
 
recipient_name: STRING_8
 
recipient_name: STRING_8
Line 135: Line 227:
 
require
 
require
 
is_raisable: is_raisable
 
is_raisable: is_raisable
 
feature -- Status settings
 
 
set_data (a_data: like data)
 
-- Set data with `a_data'.
 
ensure
 
data_is_set: data = a_data
 
 
 
 
end -- class EXCEPTION
 
end -- class EXCEPTION
Line 153: Line 238:
 
create  
 
create  
 
default_create
 
default_create
 +
 +
feature -- Access
 +
 +
frozen last_exception: EXCEPTION
 +
-- Last exception
  
 
feature -- Status report
 
feature -- Status report
Line 160: Line 250:
 
ensure
 
ensure
 
not_is_ignored: not is_ignored (a_exception)
 
not_is_ignored: not is_ignored (a_exception)
 +
 +
is_ignorable (a_exception: TYPE [EXCEPTION]): BOOLEAN
 +
-- If set, type of `a_exception' is ignorable.
  
 
is_ignored (a_exception: TYPE [EXCEPTION]): BOOLEAN
 
is_ignored (a_exception: TYPE [EXCEPTION]): BOOLEAN
Line 170: Line 263:
 
catch (a_exception: TYPE [EXCEPTION])
 
catch (a_exception: TYPE [EXCEPTION])
 
-- Set type of `a_exception' is_ignored.
 
-- Set type of `a_exception' is_ignored.
 +
require
 +
a_exception_not_void: a_exception /= Void
 
ensure
 
ensure
 
is_ignored: not is_ignored (a_exception)
 
is_ignored: not is_ignored (a_exception)
Line 176: Line 271:
 
-- Make sure that any exception of code `code' will be
 
-- Make sure that any exception of code `code' will be
 
-- ignored. This is not the default.
 
-- ignored. This is not the default.
 +
require
 +
a_exception_not_void: a_exception /= Void
 +
is_ignorable: is_ignorable (a_exception)
 
ensure
 
ensure
 
is_caught: is_ignored (a_exception)
 
is_caught: is_ignored (a_exception)
Line 181: Line 279:
 
set_is_ignored (a_exception: TYPE [EXCEPTION]; a_ignored: BOOLEAN)
 
set_is_ignored (a_exception: TYPE [EXCEPTION]; a_ignored: BOOLEAN)
 
-- Set type of `a_exception' to be `a_ignored'.
 
-- Set type of `a_exception' to be `a_ignored'.
 +
require
 +
a_exception_not_void: a_exception /= Void
 +
a_ignored_implies_is_ignorable: a_ignored implies is_ignorable (a_exception)
 
ensure
 
ensure
 
is_ignored_set: is_ignored (a_exception) = a_ignored
 
is_ignored_set: is_ignored (a_exception) = a_ignored
 +
 +
end -- class EXCEPTION_MANAGER
 
</eiffel>
 
</eiffel>
  
Line 192: Line 295:
 
class ANY
 
class ANY
 
...
 
...
     default_rescue is
+
     default_rescue
 
       do
 
       do
 
       end
 
       end
 
...
 
...
 
end
 
end
 +
</eiffel>
 +
 +
== Sample code: Raising and catching developer exception ==
 +
<eiffel>
 +
class
 +
    MY_EXCEPTION
 +
 +
inherit
 +
    DEVELOPER_EXCEPTION
 +
 +
end
 +
</eiffel>
 +
<eiffel>
 +
class
 +
    A
 +
 +
feature
 +
 +
    f
 +
        local
 +
            retried: BOOLEAN
 +
        do
 +
            if not retried then
 +
                my_exception.raise  -- Raise user-defined exception.
 +
            end
 +
        rescue
 +
            if last_exception = my_exception then  -- Check the exception object was the one user defined.
 +
                print ("True" + "%N")
 +
            else
 +
                print ("False" + "%N")
 +
            end
 +
        end
 +
 +
    my_exception: MY_EXCEPTION
 +
        once
 +
            create Result
 +
        end
 +
 +
    end
 +
</eiffel>
 +
<eiffel>
 +
class
 +
    APPLICATION
 +
 +
inherit
 +
    A
 +
 +
create
 +
    make
 +
 +
feature -- Initialization
 +
 +
    make
 +
            -- Run application.
 +
        local
 +
            a: A
 +
            retried: BOOLEAN
 +
        do
 +
            if not retried then
 +
                create a
 +
                a.f
 +
            end
 +
        rescue
 +
            retried := True
 +
               
 +
            -- `last_exception' is an object of ROUTINE_FAILURE?
 +
            if attached {ROUTINE_FAILURE} (create {EXCEPTION_MANAGER}).last_exception as l_exception then
 +
                print ("True" + "%N")
 +
            else
 +
                print ("False" + "%N")
 +
            end
 +
               
 +
            -- `original' exception is the one caused `last_exception'?
 +
            if last_exception.original = my_exception then 
 +
                print ("True" + "%N")
 +
            else
 +
                print ("False" + "%N")
 +
            end
 +
            retry
 +
        end
 +
 +
end -- class APPLICATION
 
</eiffel>
 
</eiffel>

Latest revision as of 03:17, 21 January 2016

Overview

This article describes many aspects of Exceptions as Objects (ECMA-367 8.26) which will be implemented in ISE Eiffel. All exceptions will be raised as objects which can be accessed by `last_exception'. Exceptions as objects are known as type EXCEPTION and its descendants. EXCEPTION_MANAGER is introduced to handle common exception class operations, i.e. catch, and ignore.

This doc is from the original working version: http://docs.google.com/Doc?docid=dckspcv8_9htpfm4&hl=en

Exception class hierarchy

 EXCEPTION
    SYSTEM_EXCEPTION
       MACHINE_EXCEPTION
          OPERATING_SYSTEM_EXCEPTION
             COM_FAILURE
             OPERATING_SYSTEM_FAILURE
             OPERATING_SYSTEM_SIGNAL_FAILURE
          HARDWARE_EXCEPTION
             FLOATING_POINT_FAILURE
       EIFFEL_EXCEPTION
          LANGUAGE_EXCEPTION
             BAD_INSPECT_VALUE
             VOID_TARGET
             VOID_ASSIGNED_TO_EXPANDED
             ROUTINE_FAILURE
             EIFFELSTUDIO_SPECIFIC_LANGUAGE_EXCEPTION
                CREATE_ON_DEFERRED
                ADDRESS_APPLIED_TO_MELTED_FEATURE
          EIFFEL_RUNTIME_EXCEPTION
             NO_MORE_MEMORY
             DATA_EXCEPTION
                IO_FAILURE
                SERIALIZATION_FAILURE
                MISMATCH_FAILURE
             EXTERNAL_FAILURE-- Only used for threads at the moment
             EIFFEL_RUNTIME_PANIC               
   ASSERTION_VIOLATION
      INVARIANT_VIOLATION
      PRECONDITION_VIOLATION
      POSTCONDITION_VIOLATION
      CHECK_VIOLATION
      VARIANT_VIOLATION
      OLD_VIOLATION
      LOOP_INVARIANT_VIOLATION
   DEVELOPER_EXCEPTION
   OBSOLETE_EXCEPTION     
      RESUMPTION_FAILURE Was RESUMPTION_FAILED.
      RESCUE_FAILURE --------- SHOULD NOT APPLY ANY MORE WITH ISO/ECMA, CHECK!!!
      EXCEPTION_IN_SIGNAL_HANDLER_FAILURE

Classes in red plus EXCEPTION_MANAGER will be placed at base\elks\kernel\exceptions\. The rests are ise specific.
Terminology We use _EXCEPTION for intermediate nodes in the hierarchy; when we need a term in the leaves of the hierarchy we don't use EXCEPTION but

   * _VIOLATION for assertions (also used for ASSERTION_VIOLATION, an intermediate node)
   * _FAILURE otherwise
 
 This is consistent with Eiffel exception terminology since from the viewpoint of Eiffel these things have failed, for example a signal was not handled properly. The Eiffel runtime is causing an exception in the Eiffel code as a result, but the original event was a failure.  Hence SERIALIZATION_FAILURE etc.

Raise and catch an exception

Catching an exception

All exceptions can possibly be caught. `is_caught' is set by default. Only the given type of exception is `ignore'd in EXCEPTION_MANAGER if possible, it hence is not caught. The caught exception can be accessed by `last_exception'.

Raising an exception

There are two types of exceptions concerning how an exception is raised.

  • System raised

Exception raised through the runtime. Most exceptions of this type are predefine as classes in base library. i.e. assertion violations, no memory exceptions and routine failures.

  • User raised

User raised exceptions are initialized by users and raised by explicit call of {EXCEPTION}.raise.

Theoretically the runtime can raise any exceptions known. A user can only raise an EXCEPTION that is `is_raisable'. `is_raisable' is possible true only when the exception is of DEVELOPER_EXCEPTION. This means only raising a DEVELOPER_EXCEPTION or its descendant is guaranteed correct.

Ignoring, continuing an exception

Quote from ECMA 8.26.12:

 It is possible, through routines of the Kernel Library class EXCEPTION, to ensure that exceptions of certain types be:
 
 * Ignored: lead to no change of non-exception semantics.
 * Continued: lead to execution of a programmer-specified routine, then to continuation of the execution according to non-exception semantics.

An ignorable exception can be ignored. When an exception is ignored, the raising does nothing as if non-exception semantics. What are the exceptions not ignorable?

Related queries in EXCEPTION:

is_ignored: BOOLEAN
is_caught: BOOLEAN
is_ignorable: BOOLEAN

Related routines in EXCEPTION_MANAGER:

is_caught (a_exception: TYPE [EXCEPTION]): BOOLEAN
is_ignored (a_exception: TYPE [EXCEPTION]): BOOLEAN
is_ignorable (a_exception: TYPE [EXCEPTION]): BOOLEAN
catch (a_exception: TYPE [EXCEPTION]) 
ignore (a_exception: TYPE [EXCEPTION]) 
set_is_ignored (a_exception: TYPE [EXCEPTION]; a_ignored: BOOLEAN)

`origin' VS `cause'

  • The origin of an exception is, among all exceptions that have so far been triggered but not handled, the most recent one that is not a ROUTINE_FAILURE. Because a ROUTINE_FAILURE is always the result of an exception of another kind, the `origin' is always defined.
  • The `cause' of an exception is only interesting in the case of an exception triggered in a rescue clause. In that case the exception is the result of incomplete handling of another exception (which might be a ROUTINE_FAILURE or any other kind). Then the `cause' is that other exception.
  • If an exception was not triggered in a rescue clause, its `cause' is the exception itself.

Exception at rescue clause

See the following diagram:

Exception in rescue.png

Exception e2 is kept as `cause' at d.f4 in which e3 is raised, and being called in rescue clause r2. In this case e3 is accessible by `last_exception' and e2 is accessible by `cause' of e3.

A behavior should be clarified, that when an exception occurs deep in execution level of a rescue clause, `last_exception' is understood as "last unhandled exception".
1. A new exception causes "last_exception" to be saved somewhere before entering "rescue" clause. After that the new exception object is attached to "last_exception".

2. If an exception is not handled (there is no rescue clause or "retry" is not performed), a new exception object "ROUTINE_FAILURE" is created, its attribute "original_exception" is set to "last_exception", and "last_exception" is set to this new "ROUTINE_FAILURE" object.

3. If an exception is handled ("retry" is executed), "last_exception" is attached a value saved in step 1.

Example: If "last_exception" in the following code snippet is modified by the call to feature "h" that raises an exception internally and handles it?

rescue
                -- "last_exception" is set to "X".
                -- Call feature that raises exception "Y", but handles it.
            h
 
                -- Is "last_exception" set to "X" or to "Y"?
                -- The answer is X.

OLD_VIOLATION

OLD_VIOLATION behaves similarly with ROUTINE_FAILURE. In other words, OLD_VIOLATION is never a "root" exception of an exception chain. According to ECMA 8.26.11, OLD_VIOLATION should be treated as a "root" exception. But I believe it is more interesting to know the cause (original exception) of the old voilation. This will be clarified soon.

Class ANY

This is now done in EXCEPTION_MANAGER.

class ANY
...
feature -- Exception
 
    frozen last_exception: EXCEPTION
            -- Last exception
        external
            "built_in"
        end
...

Class EXCEPTION

deferred class interface
	EXCEPTION
 
feature -- Access
 
	code: INTEGER_32
			-- Code of the exception.
			-- |Maybe we don't need this anymore
 
	exception_trace: STRING_8
			-- String representation of current exception trace
 
	meaning: STRING_8
			-- A message in English describing what `except' is
 
	message: STRING_8
			-- Tag of current exception
 
	original: EXCEPTION
			-- Original exception that triggered current exception
 
	cause: EXCEPTION
			-- Unhandled exception before current exception was triggered in a rescue clause
 
	recipient_name: STRING_8
			-- Name of the routine whose execution was
			-- interrupted by current exception
 
	type_name: STRING_8
			-- Name of the class that includes the recipient
			-- of original form of current exception
 
feature -- Status report
 
	is_caught: BOOLEAN
			-- If set, exception is raised.
		ensure
			not_is_caught_implies_is_ignorable: not Result implies is_ignorable
			not_is_ignored: not is_ignored
 
	is_ignorable: BOOLEAN
			-- Is current exception ignorable?
 
	is_ignored: BOOLEAN
			-- If set, no exception is raised.
		ensure
			is_ignored_implies_is_ignorable: Result implies is_ignorable
			not_is_caught: not is_caught
 
	is_raisable: BOOLEAN
			-- Is current exception raisable by raise?
 
feature -- Raise
 
	raise
			-- Raise current exception
		require
			is_raisable: is_raisable
 
end -- class EXCEPTION

Class EXCEPTION_MANAGER

class interface
	EXCEPTION_MANAGER
 
create 
	default_create
 
feature -- Access
 
	frozen last_exception: EXCEPTION
			-- Last exception
 
feature -- Status report
 
	is_caught (a_exception: TYPE [EXCEPTION]): BOOLEAN
			-- If set, type of `a_exception' is raised.
		ensure
			not_is_ignored: not is_ignored (a_exception)
 
	is_ignorable (a_exception: TYPE [EXCEPTION]): BOOLEAN
			-- If set, type of `a_exception' is ignorable.
 
	is_ignored (a_exception: TYPE [EXCEPTION]): BOOLEAN
			-- If set, type of `a_exception' is not raised.
		ensure
			not_is_caught: not is_caught (a_exception)
 
feature -- Status setting
 
	catch (a_exception: TYPE [EXCEPTION])
			-- Set type of `a_exception' is_ignored.
		require
			a_exception_not_void: a_exception /= Void
		ensure
			is_ignored: not is_ignored (a_exception)
 
	ignore (a_exception: TYPE [EXCEPTION])
			-- Make sure that any exception of code `code' will be
			-- ignored. This is not the default.
		require
			a_exception_not_void: a_exception /= Void
			is_ignorable: is_ignorable (a_exception)
		ensure
			is_caught: is_ignored (a_exception)
 
	set_is_ignored (a_exception: TYPE [EXCEPTION]; a_ignored: BOOLEAN)
			-- Set type of `a_exception' to be `a_ignored'.
		require
			a_exception_not_void: a_exception /= Void
			a_ignored_implies_is_ignorable: a_ignored implies is_ignorable (a_exception)
		ensure
			is_ignored_set: is_ignored (a_exception) = a_ignored
 
end -- class EXCEPTION_MANAGER

Default rescue

As specified in ECMA, `default_rescue' in ANY or its descendant is called as unqualified when an internal routine or an attributes with no rescue clause fails. We choose not to invoke it when it is not redefined, or this will be too expensive.

class ANY
...
    default_rescue
       do
       end
...
end

Sample code: Raising and catching developer exception

class
    MY_EXCEPTION
 
inherit
    DEVELOPER_EXCEPTION
 
end
class
    A
 
feature
 
    f
        local
            retried: BOOLEAN
        do
            if not retried then
                my_exception.raise   -- Raise user-defined exception.
            end
        rescue
            if last_exception = my_exception then   -- Check the exception object was the one user defined.
                print ("True" + "%N")
            else
                print ("False" + "%N")
            end
        end
 
    my_exception: MY_EXCEPTION
        once
            create Result
        end
 
    end
class
    APPLICATION
 
inherit
    A
 
create
    make
 
feature -- Initialization
 
    make
            -- Run application.
        local
            a: A
            retried: BOOLEAN
        do
            if not retried then
                create a
                a.f
            end
        rescue
            retried := True
 
            -- `last_exception' is an object of ROUTINE_FAILURE?
            if attached {ROUTINE_FAILURE} (create {EXCEPTION_MANAGER}).last_exception as l_exception then
                print ("True" + "%N")
            else
                print ("False" + "%N")
            end
 
            -- `original' exception is the one caused `last_exception'?
            if last_exception.original = my_exception then   
                print ("True" + "%N")
            else
                print ("False" + "%N")
            end
            retry
        end
 
end -- class APPLICATION