[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> </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. 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> </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> </DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>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.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN> </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. Instead people are just using code that (now)
reads:</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN> </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> </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> </DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>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.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN> </DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>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.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN> </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. (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> </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. 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.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN> </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). 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.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN> </DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>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.</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN> </DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>I've illustrated this use in
itkShrinkImageFilterTest.cxx. The syntax looks like</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN> </DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>try </FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2> {</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT
size=2> filter->Update();</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2> }</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>catch
(InvalidRequestedRegionError)</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2> {</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>
filter->ResetPipeline();</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>
filter->UpdateLargestPossibleRegion();</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2> }</FONT></SPAN></DIV>
<DIV><SPAN class=654342012-13092001></SPAN> </DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2>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.</FONT></SPAN><SPAN
class=654342012-13092001><FONT size=2> 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> </DIV>
<DIV><SPAN class=654342012-13092001><FONT size=2></FONT></SPAN> </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 & Computer Vision<BR>GE
Corporate Research & 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 <<A
href="mailto:millerjv@crd.ge.com">mailto:millerjv@crd.ge.com</A>></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> </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--