[Insight-developers] Exceptions and Pipelines

Miller, James V (CRD) millerjv@crd.ge.com
Thu, 13 Sep 2001 08:53:23 -0400


This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

------_=_NextPart_000_01C13C53.12A2B610
Content-Type: multipart/alternative;
	boundary="----_=_NextPart_001_01C13C53.12A2B610"


------_=_NextPart_001_01C13C53.12A2B610
Content-Type: text/plain;
	charset="iso-8859-1"

I have made some changes to the exception classes that I wanted to inform people about.
 
I modified the base ExceptionObject class so that its constructor can take two parameters: a string
and unsigned int.  I would like people to use the following syntax when creating an ExceptionObject
 
ExceptionObject(__FILE__, __LINE__);
 
The file and line get cached in the ExceptionObject and can be printed.  This is not entirely useful
for a runtime system trying to recover from an exception, however, an exception can be caught far far
far from where it was thrown.  Caching the file and line where the exception was created can greatly
help debugging.
 
In making this change, it is apparent that not everyone is using the "location" and "description"
attributes of the ExceptionObject.  Instead people are just using code that (now) reads:
 
if (some_error)
{
throw ExceptionObject(__FILE__, __LINE__)
}
 
This is nice compact code, but it does not provide much information to the application writer.
 
People should be subclassing the ExceptionObject for different exception types.  I just added a
DataObjectError exception object with one subclass that is an InvalidRequestedRegionError. If people
do not want to have to specify the description of their exception when they are throwing the
exception, they should subclass the ExceptionObject and set the description field in the constructor.
Subclassing has the added benefit that it allows you to add additional information that may help the
application writer determine how to recover.  For instance, I have my InvalidRequestedRegionError
keep a smart pointer to the DataObject that complained.  The application could choose just to modify
that DataObject returned and continue.
 
There are a number of subclasses of ExceptionObject already.  Some of the constructor signatures have
the an argument which is the location/description.  We should standardize on one way to construct and
throw an exception.
 
While subclassing ExceptionObject is the right thing to do, we need to be careful not to define too
too many exceptions.  (I actually toyed with the idea of defining a macro like itkTypeMacro that
would define a subclass of ExceptionObject for every class in the system). 
 
Unfortunately, I do not think that we can keep all the exceptions defined in one file.  For instance,
the DataObjectError exception that I just added allows you to pass back a (smart) pointer to the
DataObject that had the error. This helps the application writer determine where in the pipeline the
error occurred.  To get this exception object to build, I had to define in the DataObject.h file.  I
guess the message here is that there should be a global list of exceptions somewhere, perhaps using
doxygen's "\ingroup" mechanism.
 
The pipeline mechanism now throws an exception is an invalid requested region is specified (something
outside the largest possible region).  This can occur either through operator error and in some cases
by parameter changes to a filter.  For instance, changing the shrink factors on a shrink filter can
place the previous requested region outside the new largest possible region.
 
When an invalid requested region is found, an InvalidRequestedRegionError exception is thrown.  Your
application may be able to recover from this exception.  Unfortunately, since the exception is thrown
in the middle of the update mechanism, the pipeline is in an inconsistent state.  To recover, I added
the method ResetPipeline() to ProcessObject and DataObject.  ResetPipeline() will travel up the
pipeline resetting things so that an Update() can be called on the pipeline again.
 
I've illustrated this use in itkShrinkImageFilterTest.cxx.  The syntax looks like
 
try 
  {
  filter->Update();
  }
catch (InvalidRequestedRegionError)
  {
  filter->ResetPipeline();
  filter->UpdateLargestPossibleRegion();
  }
 
Another lesson learned:  I had great difficulty "catching" my exception.  I could "catch (...)" but I
could not "catch (InvalidRequestedRegionError)".  Turns out that in setting the description for my
exception object (before my call to throw), I was causing another exception to be thrown.  So the
exception propagating up the system was not the exception I was creating. Much confusion.
 
 


Jim Miller 
_____________________________________
Visualization & Computer Vision
GE Corporate Research & Development
Bldg. KW, Room C218B
P.O. Box 8, Schenectady NY 12301

millerjv@crd.ge.com < mailto:millerjv@crd.ge.com <mailto:millerjv@crd.ge.com> >
(518) 387-4005, Dial Comm: 8*833-4005, 
Cell: (518) 505-7065, Fax: (518) 387-6981 


 

------_=_NextPart_001_01C13C53.12A2B610
Content-Type: text/html;
	charset="iso-8859-1"

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">


<META content="MSHTML 5.50.4611.1300" name=GENERATOR></HEAD>
<BODY>
<DIV><SPAN class=654342012-13092001><FONT size=2>I have made some changes to the 
exception classes that I wanted to inform people about.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>I modified the base 
ExceptionObject class so that its constructor can take two parameters: a string 
and unsigned int.&nbsp; I would like people to use the following syntax when 
creating an ExceptionObject</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>ExceptionObject(__FILE__, 
__LINE__);</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>The file and line get cached in 
the ExceptionObject and can be printed.&nbsp; This is not entirely useful for a 
runtime system trying to recover from an exception, however, an exception can be 
caught far far far from where it was thrown.&nbsp; Caching the file and line 
where the exception was created can greatly help debugging.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>In making this change, it is 
apparent that not everyone is using the "location" and "description" attributes 
of the ExceptionObject.&nbsp; Instead people are just using code that (now) 
reads:</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>if 
(some_error)</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>{</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>throw ExceptionObject(__FILE__, 
__LINE__)</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>}</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>This is nice compact code, but 
it does not provide much information to the application 
writer.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>People should be subclassing 
the ExceptionObject for different exception types.&nbsp; I just added a 
DataObjectError exception object with one subclass that is an 
InvalidRequestedRegionError. If people do not want to have to specify the 
description of their exception when they are throwing the exception, they should 
subclass the ExceptionObject and set the description field in the constructor. 
Subclassing has the added benefit that it allows you to add additional 
information that may help the application writer determine how to recover.&nbsp; 
For instance, I have my InvalidRequestedRegionError keep a smart pointer to the 
DataObject that complained.&nbsp; The application could choose just to modify 
that DataObject returned and continue.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>There are a number of 
subclasses of ExceptionObject already.&nbsp; Some of the constructor signatures 
have the an argument which is the location/description.&nbsp; We should 
standardize on one way to construct and throw an exception.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>While subclassing 
ExceptionObject is the right thing to do, we need to be careful not to define 
too too many exceptions.&nbsp; (I actually toyed with the idea of defining a 
macro like itkTypeMacro that would define a subclass of ExceptionObject for 
every class in the system). </FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>Unfortunately, I do not think 
that we can keep all the exceptions defined in one file.&nbsp; For instance, the 
DataObjectError exception that I just added allows you to pass back a (smart) 
pointer to the DataObject that had the error. This helps the application writer 
determine where in the pipeline the error occurred.&nbsp; To get this exception 
object to build, I had to define in the DataObject.h file.&nbsp; I guess the 
message here is that there should be a global list of exceptions somewhere, 
perhaps using doxygen's "\ingroup" mechanism.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>The pipeline mechanism now 
throws an exception is an invalid requested region is specified (something 
outside the largest possible region).&nbsp; This can occur either through 
operator error and in some cases by parameter changes to a filter.&nbsp; For 
instance, changing the shrink factors on a shrink filter can place the previous 
requested region outside the new largest possible region.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>When an invalid requested 
region is found, an InvalidRequestedRegionError exception is thrown.&nbsp; Your 
application may be able to recover from this exception.&nbsp; Unfortunately, 
since the exception is thrown in the middle of the update mechanism, the 
pipeline is in an inconsistent state.&nbsp; To recover, I added the method 
ResetPipeline() to ProcessObject and DataObject.&nbsp; ResetPipeline() will 
travel up the pipeline resetting things so that an Update() can be called on the 
pipeline again.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>I've illustrated this use in 
itkShrinkImageFilterTest.cxx.&nbsp; The syntax looks like</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>try </FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>&nbsp; {</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT 
size=2>&nbsp;&nbsp;filter-&gt;Update();</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>&nbsp; }</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>catch 
(InvalidRequestedRegionError)</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>&nbsp; {</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>&nbsp; 
filter-&gt;ResetPipeline();</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>&nbsp; 
filter-&gt;UpdateLargestPossibleRegion();</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>&nbsp; }</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>Another lesson learned:&nbsp; I 
had great difficulty "catching" my exception.&nbsp; I could "catch (...)" but I 
could not "catch&nbsp;(InvalidRequestedRegionError)".&nbsp; Turns out that in 
setting the description for my exception object (before my call to throw), I 
was&nbsp;causing another exception to&nbsp;be thrown.</FONT></SPAN><SPAN 
class=654342012-13092001><FONT size=2>&nbsp; So the exception propagating up the 
system was not the exception I was creating. Much confusion.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001></SPAN><SPAN 
class=654342012-13092001></SPAN><SPAN class=654342012-13092001><FONT 
size=2></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN>&nbsp;</DIV><BR>
<P><B><FONT face="Comic Sans MS" color=#000080>Jim Miller</FONT></B> 
<BR><B><I><FONT face=Arial color=#ff0000 
size=2>_____________________________________</FONT></I></B><I></I><BR><I></I><I><FONT 
face=Arial color=#000000 size=1>Visualization &amp; Computer Vision<BR>GE 
Corporate Research &amp; Development<BR>Bldg. KW, Room C218B<BR>P.O. Box 8, 
Schenectady NY 12301<BR><BR></FONT><U><FONT face=Arial color=#0000ff 
size=1>millerjv@crd.ge.com &lt;<A 
href="mailto:millerjv@crd.ge.com">mailto:millerjv@crd.ge.com</A>&gt;</FONT></U></I><BR><I><FONT 
face=Arial color=#000000 size=1>(518) 387-4005, Dial Comm: 8*833-4005, 
</FONT></I><BR><I><FONT face=Arial color=#000000 size=1>Cell: (518) 505-7065, 
Fax: (518) 387-6981</FONT></I> </P><BR>
<DIV>&nbsp;</DIV></BODY></HTML>

------_=_NextPart_001_01C13C53.12A2B610--

------_=_NextPart_000_01C13C53.12A2B610
Content-Type: application/octet-stream;
	name="Miller, James V (CRD).vcf"
Content-Disposition: attachment;
	filename="Miller, James V (CRD).vcf"

BEGIN:VCARD
VERSION:2.1
N:Miller;James
FN:Miller, James V (CRD)
ORG:CRD;ESL
TITLE:Computer Scientist
TEL;WORK;VOICE:*833-4005
TEL;WORK;VOICE:1 518 387-4005
ADR;WORK:;KW-C218B;P.O. Box 8;Schenectady;New York;12301;USA
LABEL;WORK;ENCODING=QUOTED-PRINTABLE:KW-C218B=0D=0AP.O. Box 8=0D=0ASchenectady, New York 12301=0D=0AUSA
EMAIL;PREF;INTERNET:millerjv@crd.ge.com
REV:20010420T140329Z
END:VCARD

------_=_NextPart_000_01C13C53.12A2B610--