You are viewing a plain text version of this content. The canonical link for it is here.
Posted to kato-spec@incubator.apache.org by Daniel Julin <dp...@us.ibm.com> on 2009/04/11 02:06:48 UTC

Re: Kato API javadoc - error handling

Steve Poole <sp...@googlemail.com> wrote on 2009-04-08 04:46:25 AM:
...
> I'm not happy with leaving things as they are, as currently the API is
not
> very programmer friendly.   I do understand the points made on this
subject
> so far but I still think that the  "no nulls" approach is the best
> approach.    Why?  here are my reasons
>
> 1 - Code robustness -  both API consumer and API provider have to deal
with
> missing or corrupt data - and this could happen anywhere at anytime.
> Programmers love to write  chained methods  like foo().getbar().getname()
> My real worry is that Joe RandomDeveloper will write his clever tool
using a
> favourite platform / dump  which then fails when run elsewhere because of
> unexpected missing data etc.

I think this issue of never returning nulls is distinct from the question
of how to properly report errors. Certainly we don't want to get nulls in
random places when there was some specific API error or problem, as this
may cause NullPointerExceptions that are indistinguishable from many other
kinds plain bugs that we may have in our code. In other words, non-buggy
code should never see NullPointerExceptions :-)

Having a dummy static or a well-defined and specific exceptions allows us
to carefully pinpoint what the problem is. As an added bonus, note that the
dummy value or the special exception can contain a "reason" string that
provides more detail about exactly what went wrong (many of the
DataUnavailable and CorruptDataExceptions thrown in the current
implementation do so already, and the DumpAnalyzer tool, for example,
prints these reason strings in the error log)

> 2 - Sensible default behaviour for missing or corrupt data -   Missing or
> corrupt data is an indicator that something is not right - what are you
> going to do with it?  Its either an "all bets are off" signal or you are
> just going to assume some default behavior.  We should do that for the
> programmer and make the API easier and friendlier to use.

Frankly, I'm not sure that we can define a reasonable default behavior that
is satisfactory for all possible use cases. I think we'd have to carefully
review a collection of real proposed used cases to be sure.

To use the DumpAnalyzer tool as an example, I can think of two main
behaviors that we use when encountering minor errors (there may be others
that just skip my mind at this time):

- sometime we print a detailed and very specific error indication, at a
very specific point in the output and in the right context. For example:

    Current Thread: [<unavailable>]

- sometime we set a flag to remember that one particular area of our
analysis is flawed, and use that knowledge to influence other parts of the
analysis. For example, while we're scanning all the JavaClassLoader and
JavaClasses to build a dictionary mapping class names to JavaClass
definitions. If we have an error while reading some of the JavaClass
instances but not all, or if we find multiple definitions of the same
class, we emit the dreaded message "Warning: class lookups may be
unreliable", but we continue building our classname dictionary, and use it
throughout the rest of the analysis. In practice, this particular example
happens a lot!



> 3 - Programmer friendlyness -   see above.   I absoletely hate the fact
that
> the current API design forces me to put try catch blocks around every
call.
> if I wanted to report the values on a object I have to do this sort of
> horror ...
>
> String field1=null;
> String field2=null;
>
> try {
>
>  field1=foo.getField1();
> }
> catch(DTFJException e} {
>    ;
> }
> try {
>
>  field2=foo.getField2();
> }
> catch(DTFJException e} {
>    ;
> }

I guess I don't get it. As a programmer, I'd like the compiler to tell me
about as many possible problems in my program at compile time, rather than
waiting until runtime tests to hope to catch all the things that I might
have forgotten to guard against. And I'm willing to pay a little price in
added ugliness and verbosity of my code, for that benefit.

And remember, if you don't want to handle errors at a fine granularity, you
don't have to put try/catch blocks everywhere. You can just put one single
global try/catch block around your entire program, and hope for the best...


>
> May be I'm arguing for a two mode approach  in which I can tell the API
if
> I want to receive exceptions or get default data.   I do know that I do
not
> want  perpertuate the above.

I guess a two mode approach would make everyone happy. But would it make
the API too complicated?



-- Daniel --

Re: Kato API javadoc - error handling

Posted by Stuart Monteith <st...@stoo.me.uk>.
That addresses the issue.
The last time I has to call an API with the visitor API I ended up using 
an unchecked exception to abort it if the visit wasn't going to be 
interesting. I did feel ashamed about doing that though :-)

Nicholas Sterling wrote:
> How about having visitObject return a boolean saying whether traversal 
> should continue?
>
> Nicholas
>
>
> Stuart Monteith wrote:
>> I think with the visitor pattern we'd have to weigh up the typical 
>> usage patterns against the loss of control it implies.
>> Certainly for the heap, you might typically do a linear scan as the 
>> locality of objects implies nothing about their relationship to one 
>> another - using a bidirectional cursor is pointless.. The loss of 
>> control means that the entire heap will be scanned, regardless of 
>> what occurs.
>>
>> I think better with examples, so say we are counting all of the 
>> instances of classes, by name:
>>
>>
>>   final Foo outside_class = ...;
>>
>>   HeapVisitor visitor = new HeapVisitor() {
>>       HashMap<String,Long> classCount = new HashMap<String,Long>();
>>       Foo inside_class = ...;
>>
>>       void visitObject( JavaObject obj )  {
>>           // Both outside_class and inside_class are visible.
>>           // Var outside_class cannot be modified, of course,
>>           // but fields in the object it refers to may.
>> 1         JavaClass clazz = obj.getJavaClass();
>> 2         String className = clazz.getName();
>>           Long count= classCount.get(className);
>>                  if (count.longValue() == 0) {
>>             classCount.put(className, 1);
>>          } else {
>>             classCount.put(className, count+1);
>>          }
>>       }
>>
>>       void handleDataUnavailable( JavaObject obj ) {
>>           // Same here.
>>           // If we didn't put this method here, the default
>>           // would just throw a DataUnavailableException.
>>       }
>>            void HandleCorruptDataException(JavaObject obj) {
>>       }
>>   };
>>
>>    try{
>>       JavaHeap heap = factory.getJavaHeap(...);
>>    }catch(CorruptDataException e) {
>>    }catch(DataUnavailableException e) {
>>    }
>>   heap.visit( visitor );
>>
>> We could get CorruptDataException at 1 and 2, one would be because of 
>> the JavaObject, the other would be because of the JavaClass it 
>> referred to. I would posit that the exception information should be 
>> sufficient to properly report the problem in most cases as the 
>> processing done in a visitor method would be to do only with the 
>> object it is passed, and anything fairly close to it, such as its 
>> classes and fields.
>>
>> Of course, how well would this work for smaller items, such as fields 
>> in classes, classes in classloaders, etc.
>> With fields, I tend to want to address them by name or get all of 
>> them from a class.
>>
>>
>>
>> Nicholas Sterling wrote:
>>> That last example, the JDBC sanitizer, is much more conventional -- 
>>> there's no handler stack.  It is essentially a combination of the 
>>> Template and Visitor design patterns.  The Template pattern is often 
>>> applied to Java exceptions, so I don't think this would be thought 
>>> of as unusual.
>>>
>>> Instance variables in the anonymous class would be accessible to 
>>> both the method doing the work and the method handling the 
>>> exceptions.  And the class could access final variables outside it:
>>>
>>>    final Foo outside_class = ...;
>>>
>>>    HeapVisitor visitor = new HeapVisitor() {
>>>
>>>        Foo inside_class = ...;
>>>
>>>        void visitObject( JavaObject obj ) {
>>>            // Both outside_class and inside_class are visible.
>>>            // Var outside_class cannot be modified, of course,
>>>            // but fields in the object it refers to may.
>>>        }
>>>
>>>        void handleDataUnavailable( JavaObject obj ) {
>>>            // Same here.
>>>            // If we didn't put this method here, the default
>>>            // would just throw a DataUnavailableException.
>>>        }
>>>    };
>>>
>>>    JavaHeap heap = factory.getJavaHeap(...);
>>>    heap.visit( visitor );
>>>
>>> Does something like that seem reasonable?
>>>
>>> Nicholas
>>>
>>>
>>>
>>> Daniel Julin wrote:
>>>> It seems to me that with all this discussion of polymorphic and 
>>>> stackable
>>>> error handlers, we're rapidly re-inventing much of the Java exception
>>>> facility, and probably rediscovering a lot of the same design
>>>> considerations that the original designers of that Java exception 
>>>> facility
>>>> faced...
>>>>
>>>> As far as I can tell, the one major difference is that, with Java
>>>> exceptions, once an exception is thrown, the flow of control is 
>>>> irrevocably
>>>> interrupted and can only resume after the exception handler, not 
>>>> back at
>>>> the point where the exception was thrown. This means that if you do 
>>>> want
>>>> fine control over your errors but don't want to interrupt a whole 
>>>> sequence
>>>> of operations, you're forced to put an explicit try/catch block at 
>>>> every
>>>> line of the program. Whereas with these proposed handlers, a single
>>>> top-level handler could presumably take care of all the errors in a
>>>> sequence of operations without interrupting that sequence.
>>>>
>>>> Is that a correct interpretation? And is there no practical way to 
>>>> achieve
>>>> the same effect with actual Java exceptions? Some sort of "continue"
>>>> statement inside a catch block, maybe?
>>>>
>>>>
>>>> On the other hand, one thing that Java try/catch blocks offer is 
>>>> controlled
>>>> access to the local variables of the method in which the try/catch 
>>>> block
>>>> resides, and to the private instance members of the object. The 
>>>> proposed
>>>> handlers, since they are executing in a separate object and a separate
>>>> method, would not enjoy a similar access. Whether this limitation 
>>>> would
>>>> prove bothersome in practice, will depend on the actual usage 
>>>> scenarios
>>>> that we face...
>>>>
>>>>
>>>> -- Daniel --
>>>>
>>>>
>>>>
>>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-14 05:39:40 PM:
>>>>  
>>>>> If we were to end up doing something like this, would we use 
>>>>> checked or
>>>>> unchecked exceptions?  If we use checked exceptions, the client will
>>>>> still have to catch the exception or say that the method throws it.
>>>>> Presumably that would defeat the purpose...
>>>>>
>>>>> Good idea on the comparison code.  I'm a little concerned that people
>>>>> may think we are overengineering the whole exception thing; once 
>>>>> we have
>>>>> the comparison code, we can run it by some folks and see whether 
>>>>> their
>>>>> brains short-circuit.
>>>>>
>>>>> It might be helpful as a reference point to consider an example with
>>>>> another API.  I was sufficiently frustrated by the unreadability 
>>>>> of my
>>>>> JDBC clients that I wrote a pair of classes, Query and Querier, that
>>>>> hide gory details, and I think it makes a big difference.  Among the
>>>>> hidden are the binding of variables and iterating through result 
>>>>> sets,
>>>>> but probably the biggest benefit is from hiding the 
>>>>> exception-handling
>>>>> logic (it closes the ResultSet for you on an exception). This is 
>>>>> what it
>>>>> looks like to use it:
>>>>>
>>>>>     // Create a query to get recent bugs.
>>>>>     static final Query recent_bugs_query = new Query(
>>>>>         "bugs submitted against a PRODUCT in the last NUM DAYS",
>>>>>         "select id, synopsis from bugs " +
>>>>>        " where product = ? and date_submitted > sysdate - ?"
>>>>>     );
>>>>>     ...
>>>>>     // Given a Connection conn and values for PRODUCT and NUM DAYS,
>>>>>     // query the DB for recent bugs and display the resulting rows.
>>>>>     new Querier( recent_bugs_query, conn, product, num_days ) {
>>>>>         public void doRow() throws SQLException {
>>>>>             System.out.println( rs.getString(1) + " " + rs.getString
>>>>>     
>>>> (2) );
>>>>  
>>>>>         }
>>>>>     }
>>>>>
>>>>> A major benefit was getting rid of that awful doubly-nested catch 
>>>>> block
>>>>> (closing the ResultSet in the catch block may throw an exception, 
>>>>> so it
>>>>> requires its own try-catch -- gaah!).
>>>>>
>>>>> The default Querier throws an exception, but you can extend 
>>>>> Querier and
>>>>> override the handleException() method to do whatever is 
>>>>> appropriate for
>>>>> your app, and they use your custom Querier throughout your 
>>>>> program, e.g.
>>>>>
>>>>>     class MyQuerier extends Querier {
>>>>>         void handleException( Exception ex ) {
>>>>>             ....
>>>>>         }
>>>>>     }
>>>>>
>>>>> Perhaps we could use a similar approach, for example providing a
>>>>> HeapQuerier class from which clients create anonymous classes to 
>>>>> do what
>>>>> they want.
>>>>>
>>>>> Nicholas
>>>>>
>>>>>
>>>>>
>>>>> Steve Poole wrote:
>>>>>  
>>>>>> On Mon, Apr 13, 2009 at 4:34 AM, Nicholas Sterling <
>>>>>> Nicholas.Sterling@sun.com> wrote:
>>>>>>
>>>>>>
>>>>>>    
>>>>>>> And a Handler (whatever it should really be called) would have 
>>>>>>> access
>>>>>>>         
>>>> to
>>>>  
>>>>>>> the previous Handler on the stack, so it could do
>>>>>>>
>>>>>>>   void handleJavaObjectUnavailable(...) {
>>>>>>>       // do some stuff, then defer to the guy beneath us on the 
>>>>>>> stack:
>>>>>>>       prevHandler().handleJavaObjectUnavailable(...);
>>>>>>>   }
>>>>>>> Nicholas
>>>>>>>
>>>>>>> This is cool -  The callback approach is sort of a half way
>>>>>>>         
>>>> housebetween a
>>>>  
>>>>>> DOM and SAX model.  It could allow us to have a default "no nulls"
>>>>>>       
>>>> approch
>>>>  
>>>>>> for an implementation but still allows for users of the API to do
>>>>>>       
>>>> something
>>>>  
>>>>>> different.
>>>>>>
>>>>>> I think we should create some comparison code segments to see 
>>>>>> what it
>>>>>>       
>>>> could
>>>>  
>>>>>> look like.
>>>>>>
>>>>>>
>>>>>>    
>>>>>>> Nicholas Sterling wrote:
>>>>>>>
>>>>>>>
>>>>>>>      
>>>>>>>> Daniel Julin wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>        
>>>>>>>>> I like that approach a lot, because it may also address the other
>>>>>>>>>             
>>>> concern
>>>>  
>>>>>>>>> that a proposed "default reasonable behavior" may not be 
>>>>>>>>> appropriate
>>>>>>>>>             
>>>> for
>>>>  
>>>>>>>>> all usage scenarios. We could probably come-up with a variety of
>>>>>>>>>             
>>>> handlers
>>>>  
>>>>>>>>> for various common behaviors, like printing a simple error 
>>>>>>>>> message,
>>>>>>>>> completely ignoring the error, and lots of other creative 
>>>>>>>>> responses.
>>>>>>>>>
>>>>>>>>> Incidentally, nothing in this discussion is particularly 
>>>>>>>>> specific to
>>>>>>>>>             
>>>> the
>>>>  
>>>>>>>>> Kato API, is it? Are we saying that, in general, we don't like
>>>>>>>>>             
>>>> exceptions
>>>>  
>>>>>>>>> as the standard mechanism to report errors in Java, and that 
>>>>>>>>> we're
>>>>>>>>> inventing new patterns?  If so, have any useful patterns been
>>>>>>>>>             
>>>> proposed
>>>>  
>>>>>>>>> and
>>>>>>>>> documented previously in the literature?
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>             
>>>>>>>> I just looked around a little, and am only seeing suggestions 
>>>>>>>> for how
>>>>>>>>           
>>>> the
>>>>  
>>>>>>>> *client* can abstract out the exception-handling logic using the
>>>>>>>>           
>>>> Template
>>>>  
>>>>>>>> design pattern.  So far I haven't seen any advice for API 
>>>>>>>> designers.
>>>>>>>>
>>>>>>>> By the way, it occurred to me that the setter can have a 
>>>>>>>> generic name
>>>>>>>> because overloading will allow us to have a method for each
>>>>>>>>           
>>>> condition:
>>>>  
>>>>>>>>   factory.setHandler( new DataUnavailableHandler( ... ) {
>>>>>>>>       ...
>>>>>>>>   } );
>>>>>>>>
>>>>>>>> Also, it might make sense to push the handler on a stack rather
>>>>>>>>           
>>>> replace
>>>>  
>>>>>>>> what is there.  That will allow independent modules to modify just
>>>>>>>>           
>>>> that
>>>>  
>>>>>>>> behavior they need to and then remove those modifications when 
>>>>>>>> they
>>>>>>>>           
>>>> are no
>>>>  
>>>>>>>> longer needed.  It also means that we can have just one Handler
>>>>>>>>           
>>>>> () class for
>>>>>  
>>>>>>>> all the handlers, e.g.
>>>>>>>>
>>>>>>>>   // Temporarily override the handling of DataUnavailable errors.
>>>>>>>>   factory.pushHandler( new Handler( ... ) {
>>>>>>>>       void handleJavaObjectUnavailable(...) {
>>>>>>>>           // handling specific for JavaObjects
>>>>>>>>       }
>>>>>>>>       void handleDataUnavailable(...) {
>>>>>>>>           // handling for all other DataUnavailable conditions
>>>>>>>>       }
>>>>>>>>       // All handler methods not overridden will simply call 
>>>>>>>> the same
>>>>>>>> method
>>>>>>>>       // for the object beneath us on the stack.  If we get to the
>>>>>>>>           
>>>> bottom,
>>>>  
>>>>>>>> the
>>>>>>>>       // handler there will throw an exception.
>>>>>>>>   } );
>>>>>>>>   // Do some work that might cause an exception.  This might 
>>>>>>>> include
>>>>>>>> calling
>>>>>>>>   // an independently written module that also wants to 
>>>>>>>> temporarily
>>>>>>>> override
>>>>>>>>   // some handler, but they will pop that before returning to us.
>>>>>>>>   factory.popHandler();
>>>>>>>>
>>>>>>>> Nicholas
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>        
>>>>>>>>> -- Daniel --,
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-11 01:48:53 AM:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>          
>>>>>>>>>> Daniel Julin wrote:
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>            
>>>>>>>>>>> I guess a two mode approach would make everyone happy. But 
>>>>>>>>>>> would
>>>>>>>>>>>                 
>>>> it
>>>>  
>>>>>>>>>>>
>>>>>>>>>>>                 
>>>>>>>>>> make
>>>>>>>>>>
>>>>>>>>>>               the API too complicated?
>>>>>>>>>>
>>>>>>>>>>            
>>>>>>>>>>>
>>>>>>>>>>>                 
>>>>>>>>>> I have some sympathy for what Steve is talking about -- maybe my
>>>>>>>>>> short-term memory is small, but when lots of single lines of 
>>>>>>>>>> code
>>>>>>>>>> inflate to 6 lines (and two indentation levels), it is 
>>>>>>>>>> definitely
>>>>>>>>>>               
>>>> harder
>>>>  
>>>>>>>>>> for me to read.  However, I wouldn't want to give up the certain
>>>>>>>>>>               
>>>> and
>>>>  
>>>>>>>>>> immediate catching of errors offered by exceptions.
>>>>>>>>>>
>>>>>>>>>> Would a mechanism like this work for the two-mode approach?
>>>>>>>>>>
>>>>>>>>>>    factory.setDataUnavailableHandler( new DataUnavailableHandler
>>>>>>>>>>               
>>>> ( ... )
>>>>  
>>>>>>>>>>
>>>>>>>>>>               
>>>>>>>>> {
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>          
>>>>>>>>>>        ...
>>>>>>>>>>    } );
>>>>>>>>>>
>>>>>>>>>> All objects created by the factory would call that object's
>>>>>>>>>> dataUnavailable() method when appropriate, passing it enough 
>>>>>>>>>> info
>>>>>>>>>>               
>>>> about
>>>>  
>>>>>>>>>> what was going on to allow the method to make interesting 
>>>>>>>>>> decisions
>>>>>>>>>> about what to do.  The default handler would always throw a
>>>>>>>>>> DataUnavailableException.
>>>>>>>>>>
>>>>>>>>>> It's hard for me to tell whether something like that would 
>>>>>>>>>> really
>>>>>>>>>> suffice in actual use.  Perhaps it would have to be 
>>>>>>>>>> finer-grained,
>>>>>>>>>>               
>>>> with
>>>>  
>>>>>>>>>> methods for javaObjectUnavailable(), imageSectionUnavailable(),
>>>>>>>>>>               
>>>> etc.
>>>>  
>>>>>>>>>> Perhaps the defaults for those would call the more generic
>>>>>>>>>> dataUnavailable() so that you could intervene for all cases 
>>>>>>>>>> and/or
>>>>>>>>>>               
>>>> for
>>>>  
>>>>>>>>>> individual cases as desired.
>>>>>>>>>>
>>>>>>>>>> Nicholas
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>               
>>>>>>>>>             
>>>>>>       
>>>>
>>>>   
>>>

Re: Kato API javadoc - error handling

Posted by Nicholas Sterling <Ni...@Sun.COM>.
How about having visitObject return a boolean saying whether traversal 
should continue?

Nicholas


Stuart Monteith wrote:
> I think with the visitor pattern we'd have to weigh up the typical 
> usage patterns against the loss of control it implies.
> Certainly for the heap, you might typically do a linear scan as the 
> locality of objects implies nothing about their relationship to one 
> another - using a bidirectional cursor is pointless.. The loss of 
> control means that the entire heap will be scanned, regardless of what 
> occurs.
>
> I think better with examples, so say we are counting all of the 
> instances of classes, by name:
>
>
>   final Foo outside_class = ...;
>
>   HeapVisitor visitor = new HeapVisitor() {
>       HashMap<String,Long> classCount = new HashMap<String,Long>();
>       Foo inside_class = ...;
>
>       void visitObject( JavaObject obj )  {
>           // Both outside_class and inside_class are visible.
>           // Var outside_class cannot be modified, of course,
>           // but fields in the object it refers to may.
> 1         JavaClass clazz = obj.getJavaClass();
> 2         String className = clazz.getName();
>           Long count= classCount.get(className);
>                  if (count.longValue() == 0) {
>             classCount.put(className, 1);
>          } else {
>             classCount.put(className, count+1);
>          }
>       }
>
>       void handleDataUnavailable( JavaObject obj ) {
>           // Same here.
>           // If we didn't put this method here, the default
>           // would just throw a DataUnavailableException.
>       }
>            void HandleCorruptDataException(JavaObject obj) {
>       }
>   };
>
>    try{
>       JavaHeap heap = factory.getJavaHeap(...);
>    }catch(CorruptDataException e) {
>    }catch(DataUnavailableException e) {
>    }
>   heap.visit( visitor );
>
> We could get CorruptDataException at 1 and 2, one would be because of 
> the JavaObject, the other would be because of the JavaClass it 
> referred to. I would posit that the exception information should be 
> sufficient to properly report the problem in most cases as the 
> processing done in a visitor method would be to do only with the 
> object it is passed, and anything fairly close to it, such as its 
> classes and fields.
>
> Of course, how well would this work for smaller items, such as fields 
> in classes, classes in classloaders, etc.
> With fields, I tend to want to address them by name or get all of them 
> from a class.
>
>
>
> Nicholas Sterling wrote:
>> That last example, the JDBC sanitizer, is much more conventional -- 
>> there's no handler stack.  It is essentially a combination of the 
>> Template and Visitor design patterns.  The Template pattern is often 
>> applied to Java exceptions, so I don't think this would be thought of 
>> as unusual.
>>
>> Instance variables in the anonymous class would be accessible to both 
>> the method doing the work and the method handling the exceptions.  
>> And the class could access final variables outside it:
>>
>>    final Foo outside_class = ...;
>>
>>    HeapVisitor visitor = new HeapVisitor() {
>>
>>        Foo inside_class = ...;
>>
>>        void visitObject( JavaObject obj ) {
>>            // Both outside_class and inside_class are visible.
>>            // Var outside_class cannot be modified, of course,
>>            // but fields in the object it refers to may.
>>        }
>>
>>        void handleDataUnavailable( JavaObject obj ) {
>>            // Same here.
>>            // If we didn't put this method here, the default
>>            // would just throw a DataUnavailableException.
>>        }
>>    };
>>
>>    JavaHeap heap = factory.getJavaHeap(...);
>>    heap.visit( visitor );
>>
>> Does something like that seem reasonable?
>>
>> Nicholas
>>
>>
>>
>> Daniel Julin wrote:
>>> It seems to me that with all this discussion of polymorphic and 
>>> stackable
>>> error handlers, we're rapidly re-inventing much of the Java exception
>>> facility, and probably rediscovering a lot of the same design
>>> considerations that the original designers of that Java exception 
>>> facility
>>> faced...
>>>
>>> As far as I can tell, the one major difference is that, with Java
>>> exceptions, once an exception is thrown, the flow of control is 
>>> irrevocably
>>> interrupted and can only resume after the exception handler, not 
>>> back at
>>> the point where the exception was thrown. This means that if you do 
>>> want
>>> fine control over your errors but don't want to interrupt a whole 
>>> sequence
>>> of operations, you're forced to put an explicit try/catch block at 
>>> every
>>> line of the program. Whereas with these proposed handlers, a single
>>> top-level handler could presumably take care of all the errors in a
>>> sequence of operations without interrupting that sequence.
>>>
>>> Is that a correct interpretation? And is there no practical way to 
>>> achieve
>>> the same effect with actual Java exceptions? Some sort of "continue"
>>> statement inside a catch block, maybe?
>>>
>>>
>>> On the other hand, one thing that Java try/catch blocks offer is 
>>> controlled
>>> access to the local variables of the method in which the try/catch 
>>> block
>>> resides, and to the private instance members of the object. The 
>>> proposed
>>> handlers, since they are executing in a separate object and a separate
>>> method, would not enjoy a similar access. Whether this limitation would
>>> prove bothersome in practice, will depend on the actual usage scenarios
>>> that we face...
>>>
>>>
>>> -- Daniel --
>>>
>>>
>>>
>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-14 05:39:40 PM:
>>>  
>>>> If we were to end up doing something like this, would we use 
>>>> checked or
>>>> unchecked exceptions?  If we use checked exceptions, the client will
>>>> still have to catch the exception or say that the method throws it.
>>>> Presumably that would defeat the purpose...
>>>>
>>>> Good idea on the comparison code.  I'm a little concerned that people
>>>> may think we are overengineering the whole exception thing; once we 
>>>> have
>>>> the comparison code, we can run it by some folks and see whether their
>>>> brains short-circuit.
>>>>
>>>> It might be helpful as a reference point to consider an example with
>>>> another API.  I was sufficiently frustrated by the unreadability of my
>>>> JDBC clients that I wrote a pair of classes, Query and Querier, that
>>>> hide gory details, and I think it makes a big difference.  Among the
>>>> hidden are the binding of variables and iterating through result sets,
>>>> but probably the biggest benefit is from hiding the exception-handling
>>>> logic (it closes the ResultSet for you on an exception). This is 
>>>> what it
>>>> looks like to use it:
>>>>
>>>>     // Create a query to get recent bugs.
>>>>     static final Query recent_bugs_query = new Query(
>>>>         "bugs submitted against a PRODUCT in the last NUM DAYS",
>>>>         "select id, synopsis from bugs " +
>>>>        " where product = ? and date_submitted > sysdate - ?"
>>>>     );
>>>>     ...
>>>>     // Given a Connection conn and values for PRODUCT and NUM DAYS,
>>>>     // query the DB for recent bugs and display the resulting rows.
>>>>     new Querier( recent_bugs_query, conn, product, num_days ) {
>>>>         public void doRow() throws SQLException {
>>>>             System.out.println( rs.getString(1) + " " + rs.getString
>>>>     
>>> (2) );
>>>  
>>>>         }
>>>>     }
>>>>
>>>> A major benefit was getting rid of that awful doubly-nested catch 
>>>> block
>>>> (closing the ResultSet in the catch block may throw an exception, 
>>>> so it
>>>> requires its own try-catch -- gaah!).
>>>>
>>>> The default Querier throws an exception, but you can extend Querier 
>>>> and
>>>> override the handleException() method to do whatever is appropriate 
>>>> for
>>>> your app, and they use your custom Querier throughout your program, 
>>>> e.g.
>>>>
>>>>     class MyQuerier extends Querier {
>>>>         void handleException( Exception ex ) {
>>>>             ....
>>>>         }
>>>>     }
>>>>
>>>> Perhaps we could use a similar approach, for example providing a
>>>> HeapQuerier class from which clients create anonymous classes to do 
>>>> what
>>>> they want.
>>>>
>>>> Nicholas
>>>>
>>>>
>>>>
>>>> Steve Poole wrote:
>>>>   
>>>>> On Mon, Apr 13, 2009 at 4:34 AM, Nicholas Sterling <
>>>>> Nicholas.Sterling@sun.com> wrote:
>>>>>
>>>>>
>>>>>     
>>>>>> And a Handler (whatever it should really be called) would have 
>>>>>> access
>>>>>>         
>>> to
>>>  
>>>>>> the previous Handler on the stack, so it could do
>>>>>>
>>>>>>   void handleJavaObjectUnavailable(...) {
>>>>>>       // do some stuff, then defer to the guy beneath us on the 
>>>>>> stack:
>>>>>>       prevHandler().handleJavaObjectUnavailable(...);
>>>>>>   }
>>>>>> Nicholas
>>>>>>
>>>>>> This is cool -  The callback approach is sort of a half way
>>>>>>         
>>> housebetween a
>>>  
>>>>> DOM and SAX model.  It could allow us to have a default "no nulls"
>>>>>       
>>> approch
>>>  
>>>>> for an implementation but still allows for users of the API to do
>>>>>       
>>> something
>>>  
>>>>> different.
>>>>>
>>>>> I think we should create some comparison code segments to see what it
>>>>>       
>>> could
>>>  
>>>>> look like.
>>>>>
>>>>>
>>>>>     
>>>>>> Nicholas Sterling wrote:
>>>>>>
>>>>>>
>>>>>>       
>>>>>>> Daniel Julin wrote:
>>>>>>>
>>>>>>>
>>>>>>>         
>>>>>>>> I like that approach a lot, because it may also address the other
>>>>>>>>             
>>> concern
>>>  
>>>>>>>> that a proposed "default reasonable behavior" may not be 
>>>>>>>> appropriate
>>>>>>>>             
>>> for
>>>  
>>>>>>>> all usage scenarios. We could probably come-up with a variety of
>>>>>>>>             
>>> handlers
>>>  
>>>>>>>> for various common behaviors, like printing a simple error 
>>>>>>>> message,
>>>>>>>> completely ignoring the error, and lots of other creative 
>>>>>>>> responses.
>>>>>>>>
>>>>>>>> Incidentally, nothing in this discussion is particularly 
>>>>>>>> specific to
>>>>>>>>             
>>> the
>>>  
>>>>>>>> Kato API, is it? Are we saying that, in general, we don't like
>>>>>>>>             
>>> exceptions
>>>  
>>>>>>>> as the standard mechanism to report errors in Java, and that we're
>>>>>>>> inventing new patterns?  If so, have any useful patterns been
>>>>>>>>             
>>> proposed
>>>  
>>>>>>>> and
>>>>>>>> documented previously in the literature?
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>             
>>>>>>> I just looked around a little, and am only seeing suggestions 
>>>>>>> for how
>>>>>>>           
>>> the
>>>  
>>>>>>> *client* can abstract out the exception-handling logic using the
>>>>>>>           
>>> Template
>>>  
>>>>>>> design pattern.  So far I haven't seen any advice for API 
>>>>>>> designers.
>>>>>>>
>>>>>>> By the way, it occurred to me that the setter can have a generic 
>>>>>>> name
>>>>>>> because overloading will allow us to have a method for each
>>>>>>>           
>>> condition:
>>>  
>>>>>>>   factory.setHandler( new DataUnavailableHandler( ... ) {
>>>>>>>       ...
>>>>>>>   } );
>>>>>>>
>>>>>>> Also, it might make sense to push the handler on a stack rather
>>>>>>>           
>>> replace
>>>  
>>>>>>> what is there.  That will allow independent modules to modify just
>>>>>>>           
>>> that
>>>  
>>>>>>> behavior they need to and then remove those modifications when they
>>>>>>>           
>>> are no
>>>  
>>>>>>> longer needed.  It also means that we can have just one Handler
>>>>>>>           
>>>> () class for
>>>>   
>>>>>>> all the handlers, e.g.
>>>>>>>
>>>>>>>   // Temporarily override the handling of DataUnavailable errors.
>>>>>>>   factory.pushHandler( new Handler( ... ) {
>>>>>>>       void handleJavaObjectUnavailable(...) {
>>>>>>>           // handling specific for JavaObjects
>>>>>>>       }
>>>>>>>       void handleDataUnavailable(...) {
>>>>>>>           // handling for all other DataUnavailable conditions
>>>>>>>       }
>>>>>>>       // All handler methods not overridden will simply call the 
>>>>>>> same
>>>>>>> method
>>>>>>>       // for the object beneath us on the stack.  If we get to the
>>>>>>>           
>>> bottom,
>>>  
>>>>>>> the
>>>>>>>       // handler there will throw an exception.
>>>>>>>   } );
>>>>>>>   // Do some work that might cause an exception.  This might 
>>>>>>> include
>>>>>>> calling
>>>>>>>   // an independently written module that also wants to temporarily
>>>>>>> override
>>>>>>>   // some handler, but they will pop that before returning to us.
>>>>>>>   factory.popHandler();
>>>>>>>
>>>>>>> Nicholas
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>         
>>>>>>>> -- Daniel --,
>>>>>>>>
>>>>>>>>
>>>>>>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-11 01:48:53 AM:
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>           
>>>>>>>>> Daniel Julin wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>             
>>>>>>>>>> I guess a two mode approach would make everyone happy. But would
>>>>>>>>>>                 
>>> it
>>>  
>>>>>>>>>>
>>>>>>>>>>                 
>>>>>>>>> make
>>>>>>>>>
>>>>>>>>>               the API too complicated?
>>>>>>>>>
>>>>>>>>>             
>>>>>>>>>>
>>>>>>>>>>                 
>>>>>>>>> I have some sympathy for what Steve is talking about -- maybe my
>>>>>>>>> short-term memory is small, but when lots of single lines of code
>>>>>>>>> inflate to 6 lines (and two indentation levels), it is definitely
>>>>>>>>>               
>>> harder
>>>  
>>>>>>>>> for me to read.  However, I wouldn't want to give up the certain
>>>>>>>>>               
>>> and
>>>  
>>>>>>>>> immediate catching of errors offered by exceptions.
>>>>>>>>>
>>>>>>>>> Would a mechanism like this work for the two-mode approach?
>>>>>>>>>
>>>>>>>>>    factory.setDataUnavailableHandler( new DataUnavailableHandler
>>>>>>>>>               
>>> ( ... )
>>>  
>>>>>>>>>
>>>>>>>>>               
>>>>>>>> {
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>           
>>>>>>>>>        ...
>>>>>>>>>    } );
>>>>>>>>>
>>>>>>>>> All objects created by the factory would call that object's
>>>>>>>>> dataUnavailable() method when appropriate, passing it enough info
>>>>>>>>>               
>>> about
>>>  
>>>>>>>>> what was going on to allow the method to make interesting 
>>>>>>>>> decisions
>>>>>>>>> about what to do.  The default handler would always throw a
>>>>>>>>> DataUnavailableException.
>>>>>>>>>
>>>>>>>>> It's hard for me to tell whether something like that would really
>>>>>>>>> suffice in actual use.  Perhaps it would have to be 
>>>>>>>>> finer-grained,
>>>>>>>>>               
>>> with
>>>  
>>>>>>>>> methods for javaObjectUnavailable(), imageSectionUnavailable(),
>>>>>>>>>               
>>> etc.
>>>  
>>>>>>>>> Perhaps the defaults for those would call the more generic
>>>>>>>>> dataUnavailable() so that you could intervene for all cases 
>>>>>>>>> and/or
>>>>>>>>>               
>>> for
>>>  
>>>>>>>>> individual cases as desired.
>>>>>>>>>
>>>>>>>>> Nicholas
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>               
>>>>>>>>             
>>>>>       
>>>
>>>   
>>

Re: Kato API javadoc - error handling

Posted by Stuart Monteith <st...@stoo.me.uk>.
With the aim of getting to a conclusion, shall we consider the use  
cases in this discussion?

For example, with a batch job, the visitor pattern (or something like  
it) might make perfect sense.
However, if we consider the Runtime Explorer, where we have an  
interactive list of objects, the visitor pattern would not make sense.

Also, does the current API provide all of the necessary information to  
satisfy these use cases?

Can I open the discussion to the following items not in the API (some  
may be already there but implicit, others irretrievable)?:

	Generics
	Inner classes
	Thread Groups
	Annotations
	Enums
	Shared classes
	JavaStackFrame/ImageStackFrame interleaving
	local variable information
	traversal over JavaObjects that are Collections, etc.
	
Are these items absences a hindrance to the use cases?
	

Regards,
	Stuart


For instance,

On 15 Apr 2009, at 20:21, Nicholas Sterling wrote:

> I'm finding this a very useful exercise.
>
> May I suggest a couple of minor tweaks:
>
>   ObjectVisitor objVisitor = new OurObjectVisitor() {
>       boolean visitField( JavaClass clazz, JavaField field, Object
>   value ) {
>           System.out.println(
>                         obj.getID()
>               + ": "  + clazz.getName()
>               + "."   + field.getSignature()
>               + " "   + field.getName()
>               + " = " + value
>           );
>           return true;
>       }
>   };
>   HeapVisitor visitor = new OurHeapVisitor() {
>       boolean visitObject( JavaObject obj )  {
>           obj.visit(objVisitor);
>           return true;
>       }
>   };
>
> That is, a single ObjectVisitor, created beforehand, can be used  
> with each object.  Also, you probably want the object visitor to  
> extend a customized OurObjectVisitor that handles exceptions.
>
> Presumably we would want the visitors to return true, to keep  
> going.  Alternatively we could supply a stopVisiting() method which  
> the visitor could call, and not return the boolean.
>
> Nicholas
>
>
> Stuart Monteith wrote:
>> I think 1. would be rejected on the basis that errors are common.
>> However, 3. would be accepted because errors are common i.e. most  
>> of the time they are logged and ignored.
>>
>> One thing I like about the Visitor pattern is that it is never left  
>> to the caller of the API to decide under what circumstances it  
>> should stop retreiving objects, the expectation is entirely on the  
>> API implementer to be able to complete. It's not the case that the  
>> API implementer might mistakenly place the responsibility for  
>> halting onto the API caller.
>>
>> The next level to examine the Visitor pattern would be to look at  
>> JavaClass and JavaField. The example I posted was of printing out  
>> all of the fields of all of the objects on the heap. The gnarly  
>> thing about this is you have to go through getting the Object, then  
>> the class, then the field, then applying them to the object.
>>
>> Would this be sensible?:
>>
>> interface ObjectVisitor {
>>   public void visitField(JavaClass clazz, JavaField field, Object  
>> value);
>> }
>>
>>      HeapVisitor visitor = new _OurHeapVisitor_() {
>>          boolean visitObject( JavaObject obj )   
>> {                        ObjectVisitor objVisitor = new  
>> ObjectVisitor() {
>>                  public void visitField(JavaClass clazz, JavaField  
>> field, Object value) {
>>                     System.out.println(obj.getID()+":  
>> "+clazz.getName()+"."+field.getSignature()+" "+field.getName()+" =  
>> "+value);
>>                  }
>>              };
>>              obj.visit(objVisitor);
>>          }
>>      };
>>
>>
>>
>> Nicholas Sterling wrote:
>>>>>>>>


Re: Kato API javadoc - error handling

Posted by Nicholas Sterling <Ni...@Sun.COM>.
I'm finding this a very useful exercise.

May I suggest a couple of minor tweaks:

    ObjectVisitor objVisitor = new OurObjectVisitor() {
        boolean visitField( JavaClass clazz, JavaField field, Object
    value ) {
            System.out.println(
                          obj.getID()
                + ": "  + clazz.getName()
                + "."   + field.getSignature()
                + " "   + field.getName()
                + " = " + value
            );
            return true;
        }
    };
    HeapVisitor visitor = new OurHeapVisitor() {
        boolean visitObject( JavaObject obj )  {
            obj.visit(objVisitor);
            return true;
        }
    };

That is, a single ObjectVisitor, created beforehand, can be used with 
each object.  Also, you probably want the object visitor to extend a 
customized OurObjectVisitor that handles exceptions.

Presumably we would want the visitors to return true, to keep going.  
Alternatively we could supply a stopVisiting() method which the visitor 
could call, and not return the boolean.

Nicholas


Stuart Monteith wrote:
> I think 1. would be rejected on the basis that errors are common.
> However, 3. would be accepted because errors are common i.e. most of 
> the time they are logged and ignored.
>
> One thing I like about the Visitor pattern is that it is never left to 
> the caller of the API to decide under what circumstances it should 
> stop retreiving objects, the expectation is entirely on the API 
> implementer to be able to complete. It's not the case that the API 
> implementer might mistakenly place the responsibility for halting onto 
> the API caller.
>
> The next level to examine the Visitor pattern would be to look at 
> JavaClass and JavaField. The example I posted was of printing out all 
> of the fields of all of the objects on the heap. The gnarly thing 
> about this is you have to go through getting the Object, then the 
> class, then the field, then applying them to the object.
>
> Would this be sensible?:
>
> interface ObjectVisitor {
>    public void visitField(JavaClass clazz, JavaField field, Object 
> value);
> }
>
>       HeapVisitor visitor = new _OurHeapVisitor_() {
>           boolean visitObject( JavaObject obj )  {           
>              ObjectVisitor objVisitor = new ObjectVisitor() {
>                   public void visitField(JavaClass clazz, JavaField 
> field, Object value) {
>                      System.out.println(obj.getID()+": 
> "+clazz.getName()+"."+field.getSignature()+" "+field.getName()+" = 
> "+value);
>                   }
>               };
>               obj.visit(objVisitor);
>           }
>       };
>
>
>
> Nicholas Sterling wrote:
>> I was just looking closer at the example code, and wondering about 
>> the location of the try-catch.  Just to make sure we're on the same 
>> page, I'd like to throw out some different possibilities for the way 
>> you would actually handle exceptions using the visitor approach.
>>
>> 1. Here we (probably unwisely) use the traditional approach, and 
>> abort heap traversal if there is an error of any kind:
>>
>>    void doObjects() {
>>
>>        HeapVisitor visitor = new HeapVisitor() {
>>            boolean visitObject( JavaObject obj )  {
>>                // do something; return true to keep going
>>            }
>>        };
>>
>>        try{
>>            JavaHeap heap = factory.getJavaHeap(...);
>>            heap.visit( visitor );
>>        } catch ( CorruptDataException e ) {
>>            ...
>>        } catch ( DataUnavailableException e ) {
>>            ...
>>        }
>>    }
>>
>> 2. Here we handle the error inside the visitor and keep going:
>>
>>    void doObjects() _throws KatoException_ {
>>
>>        HeapVisitor visitor = new HeapVisitor() {
>>            boolean visitObject( JavaObject obj )  {
>>                // do something; return true to keep going
>>            }
>>            void handleDataUnavailable( JavaObject obj ) {
>>                ...
>>            }
>>            void HandleCorruptDataException(JavaObject obj) {
>>                ...
>>            }
>>        };
>>
>>        JavaHeap heap = factory.getJavaHeap(...);
>>        heap.visit( visitor );
>>    }
>>
>> 3. Here we abstract out that error-handling into a subclass of 
>> HeapVisitor:
>>
>>    class OurHeapVisitor extends HeapVisitor {
>>            void handleDataUnavailable( JavaObject obj ) {
>>                ...
>>            }
>>            void HandleCorruptDataException(JavaObject obj) {
>>                ...
>>            }
>>    }
>>    ------------------------------------------------------------
>>    void doObjects() _throws KatoException_ {
>>
>>        HeapVisitor visitor = new _OurHeapVisitor_() {
>>            boolean visitObject( JavaObject obj )  {
>>                // do something; return true to keep going
>>            }
>>        };
>>
>>        JavaHeap heap = factory.getJavaHeap(...);
>>        heap.visit( visitor );
>>    }
>>
>> This third one, in particular, is highly readable.
>>
>> Nicholas
>>
>>
>> Stuart Monteith wrote:
>>> I think with the visitor pattern we'd have to weigh up the typical 
>>> usage patterns against the loss of control it implies.
>>> Certainly for the heap, you might typically do a linear scan as the 
>>> locality of objects implies nothing about their relationship to one 
>>> another - using a bidirectional cursor is pointless.. The loss of 
>>> control means that the entire heap will be scanned, regardless of 
>>> what occurs.
>>>
>>> I think better with examples, so say we are counting all of the 
>>> instances of classes, by name:
>>>
>>>
>>>   final Foo outside_class = ...;
>>>
>>>   HeapVisitor visitor = new HeapVisitor() {
>>>       HashMap<String,Long> classCount = new HashMap<String,Long>();
>>>       Foo inside_class = ...;
>>>
>>>       void visitObject( JavaObject obj )  {
>>>           // Both outside_class and inside_class are visible.
>>>           // Var outside_class cannot be modified, of course,
>>>           // but fields in the object it refers to may.
>>> 1         JavaClass clazz = obj.getJavaClass();
>>> 2         String className = clazz.getName();
>>>           Long count= classCount.get(className);
>>>                  if (count.longValue() == 0) {
>>>             classCount.put(className, 1);
>>>          } else {
>>>             classCount.put(className, count+1);
>>>          }
>>>       }
>>>
>>>       void handleDataUnavailable( JavaObject obj ) {
>>>           // Same here.
>>>           // If we didn't put this method here, the default
>>>           // would just throw a DataUnavailableException.
>>>       }
>>>            void HandleCorruptDataException(JavaObject obj) {
>>>       }
>>>   };
>>>
>>>    try{
>>>       JavaHeap heap = factory.getJavaHeap(...);
>>>    }catch(CorruptDataException e) {
>>>    }catch(DataUnavailableException e) {
>>>    }
>>>   heap.visit( visitor );
>>>
>>> We could get CorruptDataException at 1 and 2, one would be because 
>>> of the JavaObject, the other would be because of the JavaClass it 
>>> referred to. I would posit that the exception information should be 
>>> sufficient to properly report the problem in most cases as the 
>>> processing done in a visitor method would be to do only with the 
>>> object it is passed, and anything fairly close to it, such as its 
>>> classes and fields.
>>>
>>> Of course, how well would this work for smaller items, such as 
>>> fields in classes, classes in classloaders, etc.
>>> With fields, I tend to want to address them by name or get all of 
>>> them from a class.
>>>
>>>
>>>
>>> Nicholas Sterling wrote:
>>>> That last example, the JDBC sanitizer, is much more conventional -- 
>>>> there's no handler stack.  It is essentially a combination of the 
>>>> Template and Visitor design patterns.  The Template pattern is 
>>>> often applied to Java exceptions, so I don't think this would be 
>>>> thought of as unusual.
>>>>
>>>> Instance variables in the anonymous class would be accessible to 
>>>> both the method doing the work and the method handling the 
>>>> exceptions.  And the class could access final variables outside it:
>>>>
>>>>    final Foo outside_class = ...;
>>>>
>>>>    HeapVisitor visitor = new HeapVisitor() {
>>>>
>>>>        Foo inside_class = ...;
>>>>
>>>>        void visitObject( JavaObject obj ) {
>>>>            // Both outside_class and inside_class are visible.
>>>>            // Var outside_class cannot be modified, of course,
>>>>            // but fields in the object it refers to may.
>>>>        }
>>>>
>>>>        void handleDataUnavailable( JavaObject obj ) {
>>>>            // Same here.
>>>>            // If we didn't put this method here, the default
>>>>            // would just throw a DataUnavailableException.
>>>>        }
>>>>    };
>>>>
>>>>    JavaHeap heap = factory.getJavaHeap(...);
>>>>    heap.visit( visitor );
>>>>
>>>> Does something like that seem reasonable?
>>>>
>>>> Nicholas
>>>>
>>>>
>>>>
>>>> Daniel Julin wrote:
>>>>> It seems to me that with all this discussion of polymorphic and 
>>>>> stackable
>>>>> error handlers, we're rapidly re-inventing much of the Java exception
>>>>> facility, and probably rediscovering a lot of the same design
>>>>> considerations that the original designers of that Java exception 
>>>>> facility
>>>>> faced...
>>>>>
>>>>> As far as I can tell, the one major difference is that, with Java
>>>>> exceptions, once an exception is thrown, the flow of control is 
>>>>> irrevocably
>>>>> interrupted and can only resume after the exception handler, not 
>>>>> back at
>>>>> the point where the exception was thrown. This means that if you 
>>>>> do want
>>>>> fine control over your errors but don't want to interrupt a whole 
>>>>> sequence
>>>>> of operations, you're forced to put an explicit try/catch block at 
>>>>> every
>>>>> line of the program. Whereas with these proposed handlers, a single
>>>>> top-level handler could presumably take care of all the errors in a
>>>>> sequence of operations without interrupting that sequence.
>>>>>
>>>>> Is that a correct interpretation? And is there no practical way to 
>>>>> achieve
>>>>> the same effect with actual Java exceptions? Some sort of "continue"
>>>>> statement inside a catch block, maybe?
>>>>>
>>>>>
>>>>> On the other hand, one thing that Java try/catch blocks offer is 
>>>>> controlled
>>>>> access to the local variables of the method in which the try/catch 
>>>>> block
>>>>> resides, and to the private instance members of the object. The 
>>>>> proposed
>>>>> handlers, since they are executing in a separate object and a 
>>>>> separate
>>>>> method, would not enjoy a similar access. Whether this limitation 
>>>>> would
>>>>> prove bothersome in practice, will depend on the actual usage 
>>>>> scenarios
>>>>> that we face...
>>>>>
>>>>>
>>>>> -- Daniel --
>>>>>
>>>>>
>>>>>
>>>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-14 05:39:40 PM:
>>>>>  
>>>>>> If we were to end up doing something like this, would we use 
>>>>>> checked or
>>>>>> unchecked exceptions?  If we use checked exceptions, the client will
>>>>>> still have to catch the exception or say that the method throws it.
>>>>>> Presumably that would defeat the purpose...
>>>>>>
>>>>>> Good idea on the comparison code.  I'm a little concerned that 
>>>>>> people
>>>>>> may think we are overengineering the whole exception thing; once 
>>>>>> we have
>>>>>> the comparison code, we can run it by some folks and see whether 
>>>>>> their
>>>>>> brains short-circuit.
>>>>>>
>>>>>> It might be helpful as a reference point to consider an example with
>>>>>> another API.  I was sufficiently frustrated by the unreadability 
>>>>>> of my
>>>>>> JDBC clients that I wrote a pair of classes, Query and Querier, that
>>>>>> hide gory details, and I think it makes a big difference.  Among the
>>>>>> hidden are the binding of variables and iterating through result 
>>>>>> sets,
>>>>>> but probably the biggest benefit is from hiding the 
>>>>>> exception-handling
>>>>>> logic (it closes the ResultSet for you on an exception). This is 
>>>>>> what it
>>>>>> looks like to use it:
>>>>>>
>>>>>>     // Create a query to get recent bugs.
>>>>>>     static final Query recent_bugs_query = new Query(
>>>>>>         "bugs submitted against a PRODUCT in the last NUM DAYS",
>>>>>>         "select id, synopsis from bugs " +
>>>>>>        " where product = ? and date_submitted > sysdate - ?"
>>>>>>     );
>>>>>>     ...
>>>>>>     // Given a Connection conn and values for PRODUCT and NUM DAYS,
>>>>>>     // query the DB for recent bugs and display the resulting rows.
>>>>>>     new Querier( recent_bugs_query, conn, product, num_days ) {
>>>>>>         public void doRow() throws SQLException {
>>>>>>             System.out.println( rs.getString(1) + " " + rs.getString
>>>>>>     
>>>>> (2) );
>>>>>  
>>>>>>         }
>>>>>>     }
>>>>>>
>>>>>> A major benefit was getting rid of that awful doubly-nested catch 
>>>>>> block
>>>>>> (closing the ResultSet in the catch block may throw an exception, 
>>>>>> so it
>>>>>> requires its own try-catch -- gaah!).
>>>>>>
>>>>>> The default Querier throws an exception, but you can extend 
>>>>>> Querier and
>>>>>> override the handleException() method to do whatever is 
>>>>>> appropriate for
>>>>>> your app, and they use your custom Querier throughout your 
>>>>>> program, e.g.
>>>>>>
>>>>>>     class MyQuerier extends Querier {
>>>>>>         void handleException( Exception ex ) {
>>>>>>             ....
>>>>>>         }
>>>>>>     }
>>>>>>
>>>>>> Perhaps we could use a similar approach, for example providing a
>>>>>> HeapQuerier class from which clients create anonymous classes to 
>>>>>> do what
>>>>>> they want.
>>>>>>
>>>>>> Nicholas
>>>>>>
>>>>>>
>>>>>>
>>>>>> Steve Poole wrote:
>>>>>>  
>>>>>>> On Mon, Apr 13, 2009 at 4:34 AM, Nicholas Sterling <
>>>>>>> Nicholas.Sterling@sun.com> wrote:
>>>>>>>
>>>>>>>
>>>>>>>   
>>>>>>>> And a Handler (whatever it should really be called) would have 
>>>>>>>> access
>>>>>>>>         
>>>>> to
>>>>>  
>>>>>>>> the previous Handler on the stack, so it could do
>>>>>>>>
>>>>>>>>   void handleJavaObjectUnavailable(...) {
>>>>>>>>       // do some stuff, then defer to the guy beneath us on the 
>>>>>>>> stack:
>>>>>>>>       prevHandler().handleJavaObjectUnavailable(...);
>>>>>>>>   }
>>>>>>>> Nicholas
>>>>>>>>
>>>>>>>> This is cool -  The callback approach is sort of a half way
>>>>>>>>         
>>>>> housebetween a
>>>>>  
>>>>>>> DOM and SAX model.  It could allow us to have a default "no nulls"
>>>>>>>       
>>>>> approch
>>>>>  
>>>>>>> for an implementation but still allows for users of the API to do
>>>>>>>       
>>>>> something
>>>>>  
>>>>>>> different.
>>>>>>>
>>>>>>> I think we should create some comparison code segments to see 
>>>>>>> what it
>>>>>>>       
>>>>> could
>>>>>  
>>>>>>> look like.
>>>>>>>
>>>>>>>
>>>>>>>   
>>>>>>>> Nicholas Sterling wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>     
>>>>>>>>> Daniel Julin wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>       
>>>>>>>>>> I like that approach a lot, because it may also address the 
>>>>>>>>>> other
>>>>>>>>>>             
>>>>> concern
>>>>>  
>>>>>>>>>> that a proposed "default reasonable behavior" may not be 
>>>>>>>>>> appropriate
>>>>>>>>>>             
>>>>> for
>>>>>  
>>>>>>>>>> all usage scenarios. We could probably come-up with a variety of
>>>>>>>>>>             
>>>>> handlers
>>>>>  
>>>>>>>>>> for various common behaviors, like printing a simple error 
>>>>>>>>>> message,
>>>>>>>>>> completely ignoring the error, and lots of other creative 
>>>>>>>>>> responses.
>>>>>>>>>>
>>>>>>>>>> Incidentally, nothing in this discussion is particularly 
>>>>>>>>>> specific to
>>>>>>>>>>             
>>>>> the
>>>>>  
>>>>>>>>>> Kato API, is it? Are we saying that, in general, we don't like
>>>>>>>>>>             
>>>>> exceptions
>>>>>  
>>>>>>>>>> as the standard mechanism to report errors in Java, and that 
>>>>>>>>>> we're
>>>>>>>>>> inventing new patterns?  If so, have any useful patterns been
>>>>>>>>>>             
>>>>> proposed
>>>>>  
>>>>>>>>>> and
>>>>>>>>>> documented previously in the literature?
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>             
>>>>>>>>> I just looked around a little, and am only seeing suggestions 
>>>>>>>>> for how
>>>>>>>>>           
>>>>> the
>>>>>  
>>>>>>>>> *client* can abstract out the exception-handling logic using the
>>>>>>>>>           
>>>>> Template
>>>>>  
>>>>>>>>> design pattern.  So far I haven't seen any advice for API 
>>>>>>>>> designers.
>>>>>>>>>
>>>>>>>>> By the way, it occurred to me that the setter can have a 
>>>>>>>>> generic name
>>>>>>>>> because overloading will allow us to have a method for each
>>>>>>>>>           
>>>>> condition:
>>>>>  
>>>>>>>>>   factory.setHandler( new DataUnavailableHandler( ... ) {
>>>>>>>>>       ...
>>>>>>>>>   } );
>>>>>>>>>
>>>>>>>>> Also, it might make sense to push the handler on a stack rather
>>>>>>>>>           
>>>>> replace
>>>>>  
>>>>>>>>> what is there.  That will allow independent modules to modify 
>>>>>>>>> just
>>>>>>>>>           
>>>>> that
>>>>>  
>>>>>>>>> behavior they need to and then remove those modifications when 
>>>>>>>>> they
>>>>>>>>>           
>>>>> are no
>>>>>  
>>>>>>>>> longer needed.  It also means that we can have just one Handler
>>>>>>>>>           
>>>>>> () class for
>>>>>>  
>>>>>>>>> all the handlers, e.g.
>>>>>>>>>
>>>>>>>>>   // Temporarily override the handling of DataUnavailable errors.
>>>>>>>>>   factory.pushHandler( new Handler( ... ) {
>>>>>>>>>       void handleJavaObjectUnavailable(...) {
>>>>>>>>>           // handling specific for JavaObjects
>>>>>>>>>       }
>>>>>>>>>       void handleDataUnavailable(...) {
>>>>>>>>>           // handling for all other DataUnavailable conditions
>>>>>>>>>       }
>>>>>>>>>       // All handler methods not overridden will simply call 
>>>>>>>>> the same
>>>>>>>>> method
>>>>>>>>>       // for the object beneath us on the stack.  If we get to 
>>>>>>>>> the
>>>>>>>>>           
>>>>> bottom,
>>>>>  
>>>>>>>>> the
>>>>>>>>>       // handler there will throw an exception.
>>>>>>>>>   } );
>>>>>>>>>   // Do some work that might cause an exception.  This might 
>>>>>>>>> include
>>>>>>>>> calling
>>>>>>>>>   // an independently written module that also wants to 
>>>>>>>>> temporarily
>>>>>>>>> override
>>>>>>>>>   // some handler, but they will pop that before returning to us.
>>>>>>>>>   factory.popHandler();
>>>>>>>>>
>>>>>>>>> Nicholas
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>       
>>>>>>>>>> -- Daniel --,
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-11 01:48:53 AM:
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>         
>>>>>>>>>>> Daniel Julin wrote:
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>           
>>>>>>>>>>>> I guess a two mode approach would make everyone happy. But 
>>>>>>>>>>>> would
>>>>>>>>>>>>                 
>>>>> it
>>>>>  
>>>>>>>>>>>>
>>>>>>>>>>>>                 
>>>>>>>>>>> make
>>>>>>>>>>>
>>>>>>>>>>>               the API too complicated?
>>>>>>>>>>>
>>>>>>>>>>>           
>>>>>>>>>>>>
>>>>>>>>>>>>                 
>>>>>>>>>>> I have some sympathy for what Steve is talking about -- 
>>>>>>>>>>> maybe my
>>>>>>>>>>> short-term memory is small, but when lots of single lines of 
>>>>>>>>>>> code
>>>>>>>>>>> inflate to 6 lines (and two indentation levels), it is 
>>>>>>>>>>> definitely
>>>>>>>>>>>               
>>>>> harder
>>>>>  
>>>>>>>>>>> for me to read.  However, I wouldn't want to give up the 
>>>>>>>>>>> certain
>>>>>>>>>>>               
>>>>> and
>>>>>  
>>>>>>>>>>> immediate catching of errors offered by exceptions.
>>>>>>>>>>>
>>>>>>>>>>> Would a mechanism like this work for the two-mode approach?
>>>>>>>>>>>
>>>>>>>>>>>    factory.setDataUnavailableHandler( new 
>>>>>>>>>>> DataUnavailableHandler
>>>>>>>>>>>               
>>>>> ( ... )
>>>>>  
>>>>>>>>>>>
>>>>>>>>>>>               
>>>>>>>>>> {
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>         
>>>>>>>>>>>        ...
>>>>>>>>>>>    } );
>>>>>>>>>>>
>>>>>>>>>>> All objects created by the factory would call that object's
>>>>>>>>>>> dataUnavailable() method when appropriate, passing it enough 
>>>>>>>>>>> info
>>>>>>>>>>>               
>>>>> about
>>>>>  
>>>>>>>>>>> what was going on to allow the method to make interesting 
>>>>>>>>>>> decisions
>>>>>>>>>>> about what to do.  The default handler would always throw a
>>>>>>>>>>> DataUnavailableException.
>>>>>>>>>>>
>>>>>>>>>>> It's hard for me to tell whether something like that would 
>>>>>>>>>>> really
>>>>>>>>>>> suffice in actual use.  Perhaps it would have to be 
>>>>>>>>>>> finer-grained,
>>>>>>>>>>>               
>>>>> with
>>>>>  
>>>>>>>>>>> methods for javaObjectUnavailable(), imageSectionUnavailable(),
>>>>>>>>>>>               
>>>>> etc.
>>>>>  
>>>>>>>>>>> Perhaps the defaults for those would call the more generic
>>>>>>>>>>> dataUnavailable() so that you could intervene for all cases 
>>>>>>>>>>> and/or
>>>>>>>>>>>               
>>>>> for
>>>>>  
>>>>>>>>>>> individual cases as desired.
>>>>>>>>>>>
>>>>>>>>>>> Nicholas
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>               
>>>>>>>>>>             
>>>>>>>       
>>>>>
>>>>>   
>>>>
>>

Re: Kato API javadoc - error handling

Posted by Stuart Monteith <st...@stoo.me.uk>.
I think 1. would be rejected on the basis that errors are common.
However, 3. would be accepted because errors are common i.e. most of the 
time they are logged and ignored.

One thing I like about the Visitor pattern is that it is never left to 
the caller of the API to decide under what circumstances it should stop 
retreiving objects, the expectation is entirely on the API implementer 
to be able to complete. It's not the case that the API implementer might 
mistakenly place the responsibility for halting onto the API caller.

The next level to examine the Visitor pattern would be to look at 
JavaClass and JavaField. The example I posted was of printing out all of 
the fields of all of the objects on the heap. The gnarly thing about 
this is you have to go through getting the Object, then the class, then 
the field, then applying them to the object.

Would this be sensible?:

interface ObjectVisitor {
    public void visitField(JavaClass clazz, JavaField field, Object value);
}

       HeapVisitor visitor = new _OurHeapVisitor_() {
           boolean visitObject( JavaObject obj )  {           
              ObjectVisitor objVisitor = new ObjectVisitor() {
                   public void visitField(JavaClass clazz, JavaField 
field, Object value) {
                      System.out.println(obj.getID()+": 
"+clazz.getName()+"."+field.getSignature()+" "+field.getName()+" = "+value);
                   }
               };
               obj.visit(objVisitor);
           }
       };



Nicholas Sterling wrote:
> I was just looking closer at the example code, and wondering about the 
> location of the try-catch.  Just to make sure we're on the same page, 
> I'd like to throw out some different possibilities for the way you 
> would actually handle exceptions using the visitor approach.
>
> 1. Here we (probably unwisely) use the traditional approach, and abort 
> heap traversal if there is an error of any kind:
>
>    void doObjects() {
>
>        HeapVisitor visitor = new HeapVisitor() {
>            boolean visitObject( JavaObject obj )  {
>                // do something; return true to keep going
>            }
>        };
>
>        try{
>            JavaHeap heap = factory.getJavaHeap(...);
>            heap.visit( visitor );
>        } catch ( CorruptDataException e ) {
>            ...
>        } catch ( DataUnavailableException e ) {
>            ...
>        }
>    }
>
> 2. Here we handle the error inside the visitor and keep going:
>
>    void doObjects() _throws KatoException_ {
>
>        HeapVisitor visitor = new HeapVisitor() {
>            boolean visitObject( JavaObject obj )  {
>                // do something; return true to keep going
>            }
>            void handleDataUnavailable( JavaObject obj ) {
>                ...
>            }
>            void HandleCorruptDataException(JavaObject obj) {
>                ...
>            }
>        };
>
>        JavaHeap heap = factory.getJavaHeap(...);
>        heap.visit( visitor );
>    }
>
> 3. Here we abstract out that error-handling into a subclass of 
> HeapVisitor:
>
>    class OurHeapVisitor extends HeapVisitor {
>            void handleDataUnavailable( JavaObject obj ) {
>                ...
>            }
>            void HandleCorruptDataException(JavaObject obj) {
>                ...
>            }
>    }
>    ------------------------------------------------------------
>    void doObjects() _throws KatoException_ {
>
>        HeapVisitor visitor = new _OurHeapVisitor_() {
>            boolean visitObject( JavaObject obj )  {
>                // do something; return true to keep going
>            }
>        };
>
>        JavaHeap heap = factory.getJavaHeap(...);
>        heap.visit( visitor );
>    }
>
> This third one, in particular, is highly readable.
>
> Nicholas
>
>
> Stuart Monteith wrote:
>> I think with the visitor pattern we'd have to weigh up the typical 
>> usage patterns against the loss of control it implies.
>> Certainly for the heap, you might typically do a linear scan as the 
>> locality of objects implies nothing about their relationship to one 
>> another - using a bidirectional cursor is pointless.. The loss of 
>> control means that the entire heap will be scanned, regardless of 
>> what occurs.
>>
>> I think better with examples, so say we are counting all of the 
>> instances of classes, by name:
>>
>>
>>   final Foo outside_class = ...;
>>
>>   HeapVisitor visitor = new HeapVisitor() {
>>       HashMap<String,Long> classCount = new HashMap<String,Long>();
>>       Foo inside_class = ...;
>>
>>       void visitObject( JavaObject obj )  {
>>           // Both outside_class and inside_class are visible.
>>           // Var outside_class cannot be modified, of course,
>>           // but fields in the object it refers to may.
>> 1         JavaClass clazz = obj.getJavaClass();
>> 2         String className = clazz.getName();
>>           Long count= classCount.get(className);
>>                  if (count.longValue() == 0) {
>>             classCount.put(className, 1);
>>          } else {
>>             classCount.put(className, count+1);
>>          }
>>       }
>>
>>       void handleDataUnavailable( JavaObject obj ) {
>>           // Same here.
>>           // If we didn't put this method here, the default
>>           // would just throw a DataUnavailableException.
>>       }
>>            void HandleCorruptDataException(JavaObject obj) {
>>       }
>>   };
>>
>>    try{
>>       JavaHeap heap = factory.getJavaHeap(...);
>>    }catch(CorruptDataException e) {
>>    }catch(DataUnavailableException e) {
>>    }
>>   heap.visit( visitor );
>>
>> We could get CorruptDataException at 1 and 2, one would be because of 
>> the JavaObject, the other would be because of the JavaClass it 
>> referred to. I would posit that the exception information should be 
>> sufficient to properly report the problem in most cases as the 
>> processing done in a visitor method would be to do only with the 
>> object it is passed, and anything fairly close to it, such as its 
>> classes and fields.
>>
>> Of course, how well would this work for smaller items, such as fields 
>> in classes, classes in classloaders, etc.
>> With fields, I tend to want to address them by name or get all of 
>> them from a class.
>>
>>
>>
>> Nicholas Sterling wrote:
>>> That last example, the JDBC sanitizer, is much more conventional -- 
>>> there's no handler stack.  It is essentially a combination of the 
>>> Template and Visitor design patterns.  The Template pattern is often 
>>> applied to Java exceptions, so I don't think this would be thought 
>>> of as unusual.
>>>
>>> Instance variables in the anonymous class would be accessible to 
>>> both the method doing the work and the method handling the 
>>> exceptions.  And the class could access final variables outside it:
>>>
>>>    final Foo outside_class = ...;
>>>
>>>    HeapVisitor visitor = new HeapVisitor() {
>>>
>>>        Foo inside_class = ...;
>>>
>>>        void visitObject( JavaObject obj ) {
>>>            // Both outside_class and inside_class are visible.
>>>            // Var outside_class cannot be modified, of course,
>>>            // but fields in the object it refers to may.
>>>        }
>>>
>>>        void handleDataUnavailable( JavaObject obj ) {
>>>            // Same here.
>>>            // If we didn't put this method here, the default
>>>            // would just throw a DataUnavailableException.
>>>        }
>>>    };
>>>
>>>    JavaHeap heap = factory.getJavaHeap(...);
>>>    heap.visit( visitor );
>>>
>>> Does something like that seem reasonable?
>>>
>>> Nicholas
>>>
>>>
>>>
>>> Daniel Julin wrote:
>>>> It seems to me that with all this discussion of polymorphic and 
>>>> stackable
>>>> error handlers, we're rapidly re-inventing much of the Java exception
>>>> facility, and probably rediscovering a lot of the same design
>>>> considerations that the original designers of that Java exception 
>>>> facility
>>>> faced...
>>>>
>>>> As far as I can tell, the one major difference is that, with Java
>>>> exceptions, once an exception is thrown, the flow of control is 
>>>> irrevocably
>>>> interrupted and can only resume after the exception handler, not 
>>>> back at
>>>> the point where the exception was thrown. This means that if you do 
>>>> want
>>>> fine control over your errors but don't want to interrupt a whole 
>>>> sequence
>>>> of operations, you're forced to put an explicit try/catch block at 
>>>> every
>>>> line of the program. Whereas with these proposed handlers, a single
>>>> top-level handler could presumably take care of all the errors in a
>>>> sequence of operations without interrupting that sequence.
>>>>
>>>> Is that a correct interpretation? And is there no practical way to 
>>>> achieve
>>>> the same effect with actual Java exceptions? Some sort of "continue"
>>>> statement inside a catch block, maybe?
>>>>
>>>>
>>>> On the other hand, one thing that Java try/catch blocks offer is 
>>>> controlled
>>>> access to the local variables of the method in which the try/catch 
>>>> block
>>>> resides, and to the private instance members of the object. The 
>>>> proposed
>>>> handlers, since they are executing in a separate object and a separate
>>>> method, would not enjoy a similar access. Whether this limitation 
>>>> would
>>>> prove bothersome in practice, will depend on the actual usage 
>>>> scenarios
>>>> that we face...
>>>>
>>>>
>>>> -- Daniel --
>>>>
>>>>
>>>>
>>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-14 05:39:40 PM:
>>>>  
>>>>> If we were to end up doing something like this, would we use 
>>>>> checked or
>>>>> unchecked exceptions?  If we use checked exceptions, the client will
>>>>> still have to catch the exception or say that the method throws it.
>>>>> Presumably that would defeat the purpose...
>>>>>
>>>>> Good idea on the comparison code.  I'm a little concerned that people
>>>>> may think we are overengineering the whole exception thing; once 
>>>>> we have
>>>>> the comparison code, we can run it by some folks and see whether 
>>>>> their
>>>>> brains short-circuit.
>>>>>
>>>>> It might be helpful as a reference point to consider an example with
>>>>> another API.  I was sufficiently frustrated by the unreadability 
>>>>> of my
>>>>> JDBC clients that I wrote a pair of classes, Query and Querier, that
>>>>> hide gory details, and I think it makes a big difference.  Among the
>>>>> hidden are the binding of variables and iterating through result 
>>>>> sets,
>>>>> but probably the biggest benefit is from hiding the 
>>>>> exception-handling
>>>>> logic (it closes the ResultSet for you on an exception). This is 
>>>>> what it
>>>>> looks like to use it:
>>>>>
>>>>>     // Create a query to get recent bugs.
>>>>>     static final Query recent_bugs_query = new Query(
>>>>>         "bugs submitted against a PRODUCT in the last NUM DAYS",
>>>>>         "select id, synopsis from bugs " +
>>>>>        " where product = ? and date_submitted > sysdate - ?"
>>>>>     );
>>>>>     ...
>>>>>     // Given a Connection conn and values for PRODUCT and NUM DAYS,
>>>>>     // query the DB for recent bugs and display the resulting rows.
>>>>>     new Querier( recent_bugs_query, conn, product, num_days ) {
>>>>>         public void doRow() throws SQLException {
>>>>>             System.out.println( rs.getString(1) + " " + rs.getString
>>>>>     
>>>> (2) );
>>>>  
>>>>>         }
>>>>>     }
>>>>>
>>>>> A major benefit was getting rid of that awful doubly-nested catch 
>>>>> block
>>>>> (closing the ResultSet in the catch block may throw an exception, 
>>>>> so it
>>>>> requires its own try-catch -- gaah!).
>>>>>
>>>>> The default Querier throws an exception, but you can extend 
>>>>> Querier and
>>>>> override the handleException() method to do whatever is 
>>>>> appropriate for
>>>>> your app, and they use your custom Querier throughout your 
>>>>> program, e.g.
>>>>>
>>>>>     class MyQuerier extends Querier {
>>>>>         void handleException( Exception ex ) {
>>>>>             ....
>>>>>         }
>>>>>     }
>>>>>
>>>>> Perhaps we could use a similar approach, for example providing a
>>>>> HeapQuerier class from which clients create anonymous classes to 
>>>>> do what
>>>>> they want.
>>>>>
>>>>> Nicholas
>>>>>
>>>>>
>>>>>
>>>>> Steve Poole wrote:
>>>>>  
>>>>>> On Mon, Apr 13, 2009 at 4:34 AM, Nicholas Sterling <
>>>>>> Nicholas.Sterling@sun.com> wrote:
>>>>>>
>>>>>>
>>>>>>    
>>>>>>> And a Handler (whatever it should really be called) would have 
>>>>>>> access
>>>>>>>         
>>>> to
>>>>  
>>>>>>> the previous Handler on the stack, so it could do
>>>>>>>
>>>>>>>   void handleJavaObjectUnavailable(...) {
>>>>>>>       // do some stuff, then defer to the guy beneath us on the 
>>>>>>> stack:
>>>>>>>       prevHandler().handleJavaObjectUnavailable(...);
>>>>>>>   }
>>>>>>> Nicholas
>>>>>>>
>>>>>>> This is cool -  The callback approach is sort of a half way
>>>>>>>         
>>>> housebetween a
>>>>  
>>>>>> DOM and SAX model.  It could allow us to have a default "no nulls"
>>>>>>       
>>>> approch
>>>>  
>>>>>> for an implementation but still allows for users of the API to do
>>>>>>       
>>>> something
>>>>  
>>>>>> different.
>>>>>>
>>>>>> I think we should create some comparison code segments to see 
>>>>>> what it
>>>>>>       
>>>> could
>>>>  
>>>>>> look like.
>>>>>>
>>>>>>
>>>>>>    
>>>>>>> Nicholas Sterling wrote:
>>>>>>>
>>>>>>>
>>>>>>>      
>>>>>>>> Daniel Julin wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>        
>>>>>>>>> I like that approach a lot, because it may also address the other
>>>>>>>>>             
>>>> concern
>>>>  
>>>>>>>>> that a proposed "default reasonable behavior" may not be 
>>>>>>>>> appropriate
>>>>>>>>>             
>>>> for
>>>>  
>>>>>>>>> all usage scenarios. We could probably come-up with a variety of
>>>>>>>>>             
>>>> handlers
>>>>  
>>>>>>>>> for various common behaviors, like printing a simple error 
>>>>>>>>> message,
>>>>>>>>> completely ignoring the error, and lots of other creative 
>>>>>>>>> responses.
>>>>>>>>>
>>>>>>>>> Incidentally, nothing in this discussion is particularly 
>>>>>>>>> specific to
>>>>>>>>>             
>>>> the
>>>>  
>>>>>>>>> Kato API, is it? Are we saying that, in general, we don't like
>>>>>>>>>             
>>>> exceptions
>>>>  
>>>>>>>>> as the standard mechanism to report errors in Java, and that 
>>>>>>>>> we're
>>>>>>>>> inventing new patterns?  If so, have any useful patterns been
>>>>>>>>>             
>>>> proposed
>>>>  
>>>>>>>>> and
>>>>>>>>> documented previously in the literature?
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>             
>>>>>>>> I just looked around a little, and am only seeing suggestions 
>>>>>>>> for how
>>>>>>>>           
>>>> the
>>>>  
>>>>>>>> *client* can abstract out the exception-handling logic using the
>>>>>>>>           
>>>> Template
>>>>  
>>>>>>>> design pattern.  So far I haven't seen any advice for API 
>>>>>>>> designers.
>>>>>>>>
>>>>>>>> By the way, it occurred to me that the setter can have a 
>>>>>>>> generic name
>>>>>>>> because overloading will allow us to have a method for each
>>>>>>>>           
>>>> condition:
>>>>  
>>>>>>>>   factory.setHandler( new DataUnavailableHandler( ... ) {
>>>>>>>>       ...
>>>>>>>>   } );
>>>>>>>>
>>>>>>>> Also, it might make sense to push the handler on a stack rather
>>>>>>>>           
>>>> replace
>>>>  
>>>>>>>> what is there.  That will allow independent modules to modify just
>>>>>>>>           
>>>> that
>>>>  
>>>>>>>> behavior they need to and then remove those modifications when 
>>>>>>>> they
>>>>>>>>           
>>>> are no
>>>>  
>>>>>>>> longer needed.  It also means that we can have just one Handler
>>>>>>>>           
>>>>> () class for
>>>>>  
>>>>>>>> all the handlers, e.g.
>>>>>>>>
>>>>>>>>   // Temporarily override the handling of DataUnavailable errors.
>>>>>>>>   factory.pushHandler( new Handler( ... ) {
>>>>>>>>       void handleJavaObjectUnavailable(...) {
>>>>>>>>           // handling specific for JavaObjects
>>>>>>>>       }
>>>>>>>>       void handleDataUnavailable(...) {
>>>>>>>>           // handling for all other DataUnavailable conditions
>>>>>>>>       }
>>>>>>>>       // All handler methods not overridden will simply call 
>>>>>>>> the same
>>>>>>>> method
>>>>>>>>       // for the object beneath us on the stack.  If we get to the
>>>>>>>>           
>>>> bottom,
>>>>  
>>>>>>>> the
>>>>>>>>       // handler there will throw an exception.
>>>>>>>>   } );
>>>>>>>>   // Do some work that might cause an exception.  This might 
>>>>>>>> include
>>>>>>>> calling
>>>>>>>>   // an independently written module that also wants to 
>>>>>>>> temporarily
>>>>>>>> override
>>>>>>>>   // some handler, but they will pop that before returning to us.
>>>>>>>>   factory.popHandler();
>>>>>>>>
>>>>>>>> Nicholas
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>        
>>>>>>>>> -- Daniel --,
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-11 01:48:53 AM:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>          
>>>>>>>>>> Daniel Julin wrote:
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>            
>>>>>>>>>>> I guess a two mode approach would make everyone happy. But 
>>>>>>>>>>> would
>>>>>>>>>>>                 
>>>> it
>>>>  
>>>>>>>>>>>
>>>>>>>>>>>                 
>>>>>>>>>> make
>>>>>>>>>>
>>>>>>>>>>               the API too complicated?
>>>>>>>>>>
>>>>>>>>>>            
>>>>>>>>>>>
>>>>>>>>>>>                 
>>>>>>>>>> I have some sympathy for what Steve is talking about -- maybe my
>>>>>>>>>> short-term memory is small, but when lots of single lines of 
>>>>>>>>>> code
>>>>>>>>>> inflate to 6 lines (and two indentation levels), it is 
>>>>>>>>>> definitely
>>>>>>>>>>               
>>>> harder
>>>>  
>>>>>>>>>> for me to read.  However, I wouldn't want to give up the certain
>>>>>>>>>>               
>>>> and
>>>>  
>>>>>>>>>> immediate catching of errors offered by exceptions.
>>>>>>>>>>
>>>>>>>>>> Would a mechanism like this work for the two-mode approach?
>>>>>>>>>>
>>>>>>>>>>    factory.setDataUnavailableHandler( new DataUnavailableHandler
>>>>>>>>>>               
>>>> ( ... )
>>>>  
>>>>>>>>>>
>>>>>>>>>>               
>>>>>>>>> {
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>          
>>>>>>>>>>        ...
>>>>>>>>>>    } );
>>>>>>>>>>
>>>>>>>>>> All objects created by the factory would call that object's
>>>>>>>>>> dataUnavailable() method when appropriate, passing it enough 
>>>>>>>>>> info
>>>>>>>>>>               
>>>> about
>>>>  
>>>>>>>>>> what was going on to allow the method to make interesting 
>>>>>>>>>> decisions
>>>>>>>>>> about what to do.  The default handler would always throw a
>>>>>>>>>> DataUnavailableException.
>>>>>>>>>>
>>>>>>>>>> It's hard for me to tell whether something like that would 
>>>>>>>>>> really
>>>>>>>>>> suffice in actual use.  Perhaps it would have to be 
>>>>>>>>>> finer-grained,
>>>>>>>>>>               
>>>> with
>>>>  
>>>>>>>>>> methods for javaObjectUnavailable(), imageSectionUnavailable(),
>>>>>>>>>>               
>>>> etc.
>>>>  
>>>>>>>>>> Perhaps the defaults for those would call the more generic
>>>>>>>>>> dataUnavailable() so that you could intervene for all cases 
>>>>>>>>>> and/or
>>>>>>>>>>               
>>>> for
>>>>  
>>>>>>>>>> individual cases as desired.
>>>>>>>>>>
>>>>>>>>>> Nicholas
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>               
>>>>>>>>>             
>>>>>>       
>>>>
>>>>   
>>>
>

Re: Kato API javadoc - error handling

Posted by Nicholas Sterling <Ni...@Sun.COM>.
I was just looking closer at the example code, and wondering about the 
location of the try-catch.  Just to make sure we're on the same page, 
I'd like to throw out some different possibilities for the way you would 
actually handle exceptions using the visitor approach.

1. Here we (probably unwisely) use the traditional approach, and abort 
heap traversal if there is an error of any kind:

    void doObjects() {

        HeapVisitor visitor = new HeapVisitor() {
            boolean visitObject( JavaObject obj )  {
                // do something; return true to keep going
            }
        };

        try{
            JavaHeap heap = factory.getJavaHeap(...);
            heap.visit( visitor );
        } catch ( CorruptDataException e ) {
            ...
        } catch ( DataUnavailableException e ) {
            ...
        }
    }

2. Here we handle the error inside the visitor and keep going:

    void doObjects() _throws KatoException_ {

        HeapVisitor visitor = new HeapVisitor() {
            boolean visitObject( JavaObject obj )  {
                // do something; return true to keep going
            }
            void handleDataUnavailable( JavaObject obj ) {
                ...
            }
            void HandleCorruptDataException(JavaObject obj) {
                ...
            }
        };

        JavaHeap heap = factory.getJavaHeap(...);
        heap.visit( visitor );
    }

3. Here we abstract out that error-handling into a subclass of HeapVisitor:

    class OurHeapVisitor extends HeapVisitor {
            void handleDataUnavailable( JavaObject obj ) {
                ...
            }
            void HandleCorruptDataException(JavaObject obj) {
                ...
            }
    }
    ------------------------------------------------------------
    void doObjects() _throws KatoException_ {

        HeapVisitor visitor = new _OurHeapVisitor_() {
            boolean visitObject( JavaObject obj )  {
                // do something; return true to keep going
            }
        };

        JavaHeap heap = factory.getJavaHeap(...);
        heap.visit( visitor );
    }

This third one, in particular, is highly readable.

Nicholas


Stuart Monteith wrote:
> I think with the visitor pattern we'd have to weigh up the typical 
> usage patterns against the loss of control it implies.
> Certainly for the heap, you might typically do a linear scan as the 
> locality of objects implies nothing about their relationship to one 
> another - using a bidirectional cursor is pointless.. The loss of 
> control means that the entire heap will be scanned, regardless of what 
> occurs.
>
> I think better with examples, so say we are counting all of the 
> instances of classes, by name:
>
>
>   final Foo outside_class = ...;
>
>   HeapVisitor visitor = new HeapVisitor() {
>       HashMap<String,Long> classCount = new HashMap<String,Long>();
>       Foo inside_class = ...;
>
>       void visitObject( JavaObject obj )  {
>           // Both outside_class and inside_class are visible.
>           // Var outside_class cannot be modified, of course,
>           // but fields in the object it refers to may.
> 1         JavaClass clazz = obj.getJavaClass();
> 2         String className = clazz.getName();
>           Long count= classCount.get(className);
>                  if (count.longValue() == 0) {
>             classCount.put(className, 1);
>          } else {
>             classCount.put(className, count+1);
>          }
>       }
>
>       void handleDataUnavailable( JavaObject obj ) {
>           // Same here.
>           // If we didn't put this method here, the default
>           // would just throw a DataUnavailableException.
>       }
>            void HandleCorruptDataException(JavaObject obj) {
>       }
>   };
>
>    try{
>       JavaHeap heap = factory.getJavaHeap(...);
>    }catch(CorruptDataException e) {
>    }catch(DataUnavailableException e) {
>    }
>   heap.visit( visitor );
>
> We could get CorruptDataException at 1 and 2, one would be because of 
> the JavaObject, the other would be because of the JavaClass it 
> referred to. I would posit that the exception information should be 
> sufficient to properly report the problem in most cases as the 
> processing done in a visitor method would be to do only with the 
> object it is passed, and anything fairly close to it, such as its 
> classes and fields.
>
> Of course, how well would this work for smaller items, such as fields 
> in classes, classes in classloaders, etc.
> With fields, I tend to want to address them by name or get all of them 
> from a class.
>
>
>
> Nicholas Sterling wrote:
>> That last example, the JDBC sanitizer, is much more conventional -- 
>> there's no handler stack.  It is essentially a combination of the 
>> Template and Visitor design patterns.  The Template pattern is often 
>> applied to Java exceptions, so I don't think this would be thought of 
>> as unusual.
>>
>> Instance variables in the anonymous class would be accessible to both 
>> the method doing the work and the method handling the exceptions.  
>> And the class could access final variables outside it:
>>
>>    final Foo outside_class = ...;
>>
>>    HeapVisitor visitor = new HeapVisitor() {
>>
>>        Foo inside_class = ...;
>>
>>        void visitObject( JavaObject obj ) {
>>            // Both outside_class and inside_class are visible.
>>            // Var outside_class cannot be modified, of course,
>>            // but fields in the object it refers to may.
>>        }
>>
>>        void handleDataUnavailable( JavaObject obj ) {
>>            // Same here.
>>            // If we didn't put this method here, the default
>>            // would just throw a DataUnavailableException.
>>        }
>>    };
>>
>>    JavaHeap heap = factory.getJavaHeap(...);
>>    heap.visit( visitor );
>>
>> Does something like that seem reasonable?
>>
>> Nicholas
>>
>>
>>
>> Daniel Julin wrote:
>>> It seems to me that with all this discussion of polymorphic and 
>>> stackable
>>> error handlers, we're rapidly re-inventing much of the Java exception
>>> facility, and probably rediscovering a lot of the same design
>>> considerations that the original designers of that Java exception 
>>> facility
>>> faced...
>>>
>>> As far as I can tell, the one major difference is that, with Java
>>> exceptions, once an exception is thrown, the flow of control is 
>>> irrevocably
>>> interrupted and can only resume after the exception handler, not 
>>> back at
>>> the point where the exception was thrown. This means that if you do 
>>> want
>>> fine control over your errors but don't want to interrupt a whole 
>>> sequence
>>> of operations, you're forced to put an explicit try/catch block at 
>>> every
>>> line of the program. Whereas with these proposed handlers, a single
>>> top-level handler could presumably take care of all the errors in a
>>> sequence of operations without interrupting that sequence.
>>>
>>> Is that a correct interpretation? And is there no practical way to 
>>> achieve
>>> the same effect with actual Java exceptions? Some sort of "continue"
>>> statement inside a catch block, maybe?
>>>
>>>
>>> On the other hand, one thing that Java try/catch blocks offer is 
>>> controlled
>>> access to the local variables of the method in which the try/catch 
>>> block
>>> resides, and to the private instance members of the object. The 
>>> proposed
>>> handlers, since they are executing in a separate object and a separate
>>> method, would not enjoy a similar access. Whether this limitation would
>>> prove bothersome in practice, will depend on the actual usage scenarios
>>> that we face...
>>>
>>>
>>> -- Daniel --
>>>
>>>
>>>
>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-14 05:39:40 PM:
>>>  
>>>> If we were to end up doing something like this, would we use 
>>>> checked or
>>>> unchecked exceptions?  If we use checked exceptions, the client will
>>>> still have to catch the exception or say that the method throws it.
>>>> Presumably that would defeat the purpose...
>>>>
>>>> Good idea on the comparison code.  I'm a little concerned that people
>>>> may think we are overengineering the whole exception thing; once we 
>>>> have
>>>> the comparison code, we can run it by some folks and see whether their
>>>> brains short-circuit.
>>>>
>>>> It might be helpful as a reference point to consider an example with
>>>> another API.  I was sufficiently frustrated by the unreadability of my
>>>> JDBC clients that I wrote a pair of classes, Query and Querier, that
>>>> hide gory details, and I think it makes a big difference.  Among the
>>>> hidden are the binding of variables and iterating through result sets,
>>>> but probably the biggest benefit is from hiding the exception-handling
>>>> logic (it closes the ResultSet for you on an exception). This is 
>>>> what it
>>>> looks like to use it:
>>>>
>>>>     // Create a query to get recent bugs.
>>>>     static final Query recent_bugs_query = new Query(
>>>>         "bugs submitted against a PRODUCT in the last NUM DAYS",
>>>>         "select id, synopsis from bugs " +
>>>>        " where product = ? and date_submitted > sysdate - ?"
>>>>     );
>>>>     ...
>>>>     // Given a Connection conn and values for PRODUCT and NUM DAYS,
>>>>     // query the DB for recent bugs and display the resulting rows.
>>>>     new Querier( recent_bugs_query, conn, product, num_days ) {
>>>>         public void doRow() throws SQLException {
>>>>             System.out.println( rs.getString(1) + " " + rs.getString
>>>>     
>>> (2) );
>>>  
>>>>         }
>>>>     }
>>>>
>>>> A major benefit was getting rid of that awful doubly-nested catch 
>>>> block
>>>> (closing the ResultSet in the catch block may throw an exception, 
>>>> so it
>>>> requires its own try-catch -- gaah!).
>>>>
>>>> The default Querier throws an exception, but you can extend Querier 
>>>> and
>>>> override the handleException() method to do whatever is appropriate 
>>>> for
>>>> your app, and they use your custom Querier throughout your program, 
>>>> e.g.
>>>>
>>>>     class MyQuerier extends Querier {
>>>>         void handleException( Exception ex ) {
>>>>             ....
>>>>         }
>>>>     }
>>>>
>>>> Perhaps we could use a similar approach, for example providing a
>>>> HeapQuerier class from which clients create anonymous classes to do 
>>>> what
>>>> they want.
>>>>
>>>> Nicholas
>>>>
>>>>
>>>>
>>>> Steve Poole wrote:
>>>>   
>>>>> On Mon, Apr 13, 2009 at 4:34 AM, Nicholas Sterling <
>>>>> Nicholas.Sterling@sun.com> wrote:
>>>>>
>>>>>
>>>>>     
>>>>>> And a Handler (whatever it should really be called) would have 
>>>>>> access
>>>>>>         
>>> to
>>>  
>>>>>> the previous Handler on the stack, so it could do
>>>>>>
>>>>>>   void handleJavaObjectUnavailable(...) {
>>>>>>       // do some stuff, then defer to the guy beneath us on the 
>>>>>> stack:
>>>>>>       prevHandler().handleJavaObjectUnavailable(...);
>>>>>>   }
>>>>>> Nicholas
>>>>>>
>>>>>> This is cool -  The callback approach is sort of a half way
>>>>>>         
>>> housebetween a
>>>  
>>>>> DOM and SAX model.  It could allow us to have a default "no nulls"
>>>>>       
>>> approch
>>>  
>>>>> for an implementation but still allows for users of the API to do
>>>>>       
>>> something
>>>  
>>>>> different.
>>>>>
>>>>> I think we should create some comparison code segments to see what it
>>>>>       
>>> could
>>>  
>>>>> look like.
>>>>>
>>>>>
>>>>>     
>>>>>> Nicholas Sterling wrote:
>>>>>>
>>>>>>
>>>>>>       
>>>>>>> Daniel Julin wrote:
>>>>>>>
>>>>>>>
>>>>>>>         
>>>>>>>> I like that approach a lot, because it may also address the other
>>>>>>>>             
>>> concern
>>>  
>>>>>>>> that a proposed "default reasonable behavior" may not be 
>>>>>>>> appropriate
>>>>>>>>             
>>> for
>>>  
>>>>>>>> all usage scenarios. We could probably come-up with a variety of
>>>>>>>>             
>>> handlers
>>>  
>>>>>>>> for various common behaviors, like printing a simple error 
>>>>>>>> message,
>>>>>>>> completely ignoring the error, and lots of other creative 
>>>>>>>> responses.
>>>>>>>>
>>>>>>>> Incidentally, nothing in this discussion is particularly 
>>>>>>>> specific to
>>>>>>>>             
>>> the
>>>  
>>>>>>>> Kato API, is it? Are we saying that, in general, we don't like
>>>>>>>>             
>>> exceptions
>>>  
>>>>>>>> as the standard mechanism to report errors in Java, and that we're
>>>>>>>> inventing new patterns?  If so, have any useful patterns been
>>>>>>>>             
>>> proposed
>>>  
>>>>>>>> and
>>>>>>>> documented previously in the literature?
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>             
>>>>>>> I just looked around a little, and am only seeing suggestions 
>>>>>>> for how
>>>>>>>           
>>> the
>>>  
>>>>>>> *client* can abstract out the exception-handling logic using the
>>>>>>>           
>>> Template
>>>  
>>>>>>> design pattern.  So far I haven't seen any advice for API 
>>>>>>> designers.
>>>>>>>
>>>>>>> By the way, it occurred to me that the setter can have a generic 
>>>>>>> name
>>>>>>> because overloading will allow us to have a method for each
>>>>>>>           
>>> condition:
>>>  
>>>>>>>   factory.setHandler( new DataUnavailableHandler( ... ) {
>>>>>>>       ...
>>>>>>>   } );
>>>>>>>
>>>>>>> Also, it might make sense to push the handler on a stack rather
>>>>>>>           
>>> replace
>>>  
>>>>>>> what is there.  That will allow independent modules to modify just
>>>>>>>           
>>> that
>>>  
>>>>>>> behavior they need to and then remove those modifications when they
>>>>>>>           
>>> are no
>>>  
>>>>>>> longer needed.  It also means that we can have just one Handler
>>>>>>>           
>>>> () class for
>>>>   
>>>>>>> all the handlers, e.g.
>>>>>>>
>>>>>>>   // Temporarily override the handling of DataUnavailable errors.
>>>>>>>   factory.pushHandler( new Handler( ... ) {
>>>>>>>       void handleJavaObjectUnavailable(...) {
>>>>>>>           // handling specific for JavaObjects
>>>>>>>       }
>>>>>>>       void handleDataUnavailable(...) {
>>>>>>>           // handling for all other DataUnavailable conditions
>>>>>>>       }
>>>>>>>       // All handler methods not overridden will simply call the 
>>>>>>> same
>>>>>>> method
>>>>>>>       // for the object beneath us on the stack.  If we get to the
>>>>>>>           
>>> bottom,
>>>  
>>>>>>> the
>>>>>>>       // handler there will throw an exception.
>>>>>>>   } );
>>>>>>>   // Do some work that might cause an exception.  This might 
>>>>>>> include
>>>>>>> calling
>>>>>>>   // an independently written module that also wants to temporarily
>>>>>>> override
>>>>>>>   // some handler, but they will pop that before returning to us.
>>>>>>>   factory.popHandler();
>>>>>>>
>>>>>>> Nicholas
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>         
>>>>>>>> -- Daniel --,
>>>>>>>>
>>>>>>>>
>>>>>>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-11 01:48:53 AM:
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>           
>>>>>>>>> Daniel Julin wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>             
>>>>>>>>>> I guess a two mode approach would make everyone happy. But would
>>>>>>>>>>                 
>>> it
>>>  
>>>>>>>>>>
>>>>>>>>>>                 
>>>>>>>>> make
>>>>>>>>>
>>>>>>>>>               the API too complicated?
>>>>>>>>>
>>>>>>>>>             
>>>>>>>>>>
>>>>>>>>>>                 
>>>>>>>>> I have some sympathy for what Steve is talking about -- maybe my
>>>>>>>>> short-term memory is small, but when lots of single lines of code
>>>>>>>>> inflate to 6 lines (and two indentation levels), it is definitely
>>>>>>>>>               
>>> harder
>>>  
>>>>>>>>> for me to read.  However, I wouldn't want to give up the certain
>>>>>>>>>               
>>> and
>>>  
>>>>>>>>> immediate catching of errors offered by exceptions.
>>>>>>>>>
>>>>>>>>> Would a mechanism like this work for the two-mode approach?
>>>>>>>>>
>>>>>>>>>    factory.setDataUnavailableHandler( new DataUnavailableHandler
>>>>>>>>>               
>>> ( ... )
>>>  
>>>>>>>>>
>>>>>>>>>               
>>>>>>>> {
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>           
>>>>>>>>>        ...
>>>>>>>>>    } );
>>>>>>>>>
>>>>>>>>> All objects created by the factory would call that object's
>>>>>>>>> dataUnavailable() method when appropriate, passing it enough info
>>>>>>>>>               
>>> about
>>>  
>>>>>>>>> what was going on to allow the method to make interesting 
>>>>>>>>> decisions
>>>>>>>>> about what to do.  The default handler would always throw a
>>>>>>>>> DataUnavailableException.
>>>>>>>>>
>>>>>>>>> It's hard for me to tell whether something like that would really
>>>>>>>>> suffice in actual use.  Perhaps it would have to be 
>>>>>>>>> finer-grained,
>>>>>>>>>               
>>> with
>>>  
>>>>>>>>> methods for javaObjectUnavailable(), imageSectionUnavailable(),
>>>>>>>>>               
>>> etc.
>>>  
>>>>>>>>> Perhaps the defaults for those would call the more generic
>>>>>>>>> dataUnavailable() so that you could intervene for all cases 
>>>>>>>>> and/or
>>>>>>>>>               
>>> for
>>>  
>>>>>>>>> individual cases as desired.
>>>>>>>>>
>>>>>>>>> Nicholas
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>               
>>>>>>>>             
>>>>>       
>>>
>>>   
>>

Re: Kato API javadoc - error handling

Posted by Stuart Monteith <st...@stoo.me.uk>.
I think with the visitor pattern we'd have to weigh up the typical usage 
patterns against the loss of control it implies.
Certainly for the heap, you might typically do a linear scan as the 
locality of objects implies nothing about their relationship to one 
another - using a bidirectional cursor is pointless.. The loss of 
control means that the entire heap will be scanned, regardless of what 
occurs.

I think better with examples, so say we are counting all of the 
instances of classes, by name:


   final Foo outside_class = ...;

   HeapVisitor visitor = new HeapVisitor() {
       HashMap<String,Long> classCount = new HashMap<String,Long>();
       Foo inside_class = ...;

       void visitObject( JavaObject obj )  {
           // Both outside_class and inside_class are visible.
           // Var outside_class cannot be modified, of course,
           // but fields in the object it refers to may.
1         JavaClass clazz = obj.getJavaClass();
2         String className = clazz.getName();
           Long count= classCount.get(className);
         
          if (count.longValue() == 0) {
             classCount.put(className, 1);
          } else {
             classCount.put(className, count+1);
          }
       }

       void handleDataUnavailable( JavaObject obj ) {
           // Same here.
           // If we didn't put this method here, the default
           // would just throw a DataUnavailableException.
       }
      
       void HandleCorruptDataException(JavaObject obj) {
       }
   };

    try{
       JavaHeap heap = factory.getJavaHeap(...);
    }catch(CorruptDataException e) {
    }catch(DataUnavailableException e) {
    }
   heap.visit( visitor );

We could get CorruptDataException at 1 and 2, one would be because of 
the JavaObject, the other would be because of the JavaClass it referred 
to. I would posit that the exception information should be sufficient to 
properly report the problem in most cases as the processing done in a 
visitor method would be to do only with the object it is passed, and 
anything fairly close to it, such as its classes and fields.

Of course, how well would this work for smaller items, such as fields in 
classes, classes in classloaders, etc.
With fields, I tend to want to address them by name or get all of them 
from a class.



Nicholas Sterling wrote:
> That last example, the JDBC sanitizer, is much more conventional -- 
> there's no handler stack.  It is essentially a combination of the 
> Template and Visitor design patterns.  The Template pattern is often 
> applied to Java exceptions, so I don't think this would be thought of 
> as unusual.
>
> Instance variables in the anonymous class would be accessible to both 
> the method doing the work and the method handling the exceptions.  And 
> the class could access final variables outside it:
>
>    final Foo outside_class = ...;
>
>    HeapVisitor visitor = new HeapVisitor() {
>
>        Foo inside_class = ...;
>
>        void visitObject( JavaObject obj ) {
>            // Both outside_class and inside_class are visible.
>            // Var outside_class cannot be modified, of course,
>            // but fields in the object it refers to may.
>        }
>
>        void handleDataUnavailable( JavaObject obj ) {
>            // Same here.
>            // If we didn't put this method here, the default
>            // would just throw a DataUnavailableException.
>        }
>    };
>
>    JavaHeap heap = factory.getJavaHeap(...);
>    heap.visit( visitor );
>
> Does something like that seem reasonable?
>
> Nicholas
>
>
>
> Daniel Julin wrote:
>> It seems to me that with all this discussion of polymorphic and 
>> stackable
>> error handlers, we're rapidly re-inventing much of the Java exception
>> facility, and probably rediscovering a lot of the same design
>> considerations that the original designers of that Java exception 
>> facility
>> faced...
>>
>> As far as I can tell, the one major difference is that, with Java
>> exceptions, once an exception is thrown, the flow of control is 
>> irrevocably
>> interrupted and can only resume after the exception handler, not back at
>> the point where the exception was thrown. This means that if you do want
>> fine control over your errors but don't want to interrupt a whole 
>> sequence
>> of operations, you're forced to put an explicit try/catch block at every
>> line of the program. Whereas with these proposed handlers, a single
>> top-level handler could presumably take care of all the errors in a
>> sequence of operations without interrupting that sequence.
>>
>> Is that a correct interpretation? And is there no practical way to 
>> achieve
>> the same effect with actual Java exceptions? Some sort of "continue"
>> statement inside a catch block, maybe?
>>
>>
>> On the other hand, one thing that Java try/catch blocks offer is 
>> controlled
>> access to the local variables of the method in which the try/catch block
>> resides, and to the private instance members of the object. The proposed
>> handlers, since they are executing in a separate object and a separate
>> method, would not enjoy a similar access. Whether this limitation would
>> prove bothersome in practice, will depend on the actual usage scenarios
>> that we face...
>>
>>
>> -- Daniel --
>>
>>
>>
>> Nicholas.Sterling@Sun.COM wrote on 2009-04-14 05:39:40 PM:
>>  
>>> If we were to end up doing something like this, would we use checked or
>>> unchecked exceptions?  If we use checked exceptions, the client will
>>> still have to catch the exception or say that the method throws it.
>>> Presumably that would defeat the purpose...
>>>
>>> Good idea on the comparison code.  I'm a little concerned that people
>>> may think we are overengineering the whole exception thing; once we 
>>> have
>>> the comparison code, we can run it by some folks and see whether their
>>> brains short-circuit.
>>>
>>> It might be helpful as a reference point to consider an example with
>>> another API.  I was sufficiently frustrated by the unreadability of my
>>> JDBC clients that I wrote a pair of classes, Query and Querier, that
>>> hide gory details, and I think it makes a big difference.  Among the
>>> hidden are the binding of variables and iterating through result sets,
>>> but probably the biggest benefit is from hiding the exception-handling
>>> logic (it closes the ResultSet for you on an exception). This is 
>>> what it
>>> looks like to use it:
>>>
>>>     // Create a query to get recent bugs.
>>>     static final Query recent_bugs_query = new Query(
>>>         "bugs submitted against a PRODUCT in the last NUM DAYS",
>>>         "select id, synopsis from bugs " +
>>>        " where product = ? and date_submitted > sysdate - ?"
>>>     );
>>>     ...
>>>     // Given a Connection conn and values for PRODUCT and NUM DAYS,
>>>     // query the DB for recent bugs and display the resulting rows.
>>>     new Querier( recent_bugs_query, conn, product, num_days ) {
>>>         public void doRow() throws SQLException {
>>>             System.out.println( rs.getString(1) + " " + rs.getString
>>>     
>> (2) );
>>  
>>>         }
>>>     }
>>>
>>> A major benefit was getting rid of that awful doubly-nested catch block
>>> (closing the ResultSet in the catch block may throw an exception, so it
>>> requires its own try-catch -- gaah!).
>>>
>>> The default Querier throws an exception, but you can extend Querier and
>>> override the handleException() method to do whatever is appropriate for
>>> your app, and they use your custom Querier throughout your program, 
>>> e.g.
>>>
>>>     class MyQuerier extends Querier {
>>>         void handleException( Exception ex ) {
>>>             ....
>>>         }
>>>     }
>>>
>>> Perhaps we could use a similar approach, for example providing a
>>> HeapQuerier class from which clients create anonymous classes to do 
>>> what
>>> they want.
>>>
>>> Nicholas
>>>
>>>
>>>
>>> Steve Poole wrote:
>>>    
>>>> On Mon, Apr 13, 2009 at 4:34 AM, Nicholas Sterling <
>>>> Nicholas.Sterling@sun.com> wrote:
>>>>
>>>>
>>>>      
>>>>> And a Handler (whatever it should really be called) would have access
>>>>>         
>> to
>>  
>>>>> the previous Handler on the stack, so it could do
>>>>>
>>>>>   void handleJavaObjectUnavailable(...) {
>>>>>       // do some stuff, then defer to the guy beneath us on the 
>>>>> stack:
>>>>>       prevHandler().handleJavaObjectUnavailable(...);
>>>>>   }
>>>>> Nicholas
>>>>>
>>>>> This is cool -  The callback approach is sort of a half way
>>>>>         
>> housebetween a
>>  
>>>> DOM and SAX model.  It could allow us to have a default "no nulls"
>>>>       
>> approch
>>  
>>>> for an implementation but still allows for users of the API to do
>>>>       
>> something
>>  
>>>> different.
>>>>
>>>> I think we should create some comparison code segments to see what it
>>>>       
>> could
>>  
>>>> look like.
>>>>
>>>>
>>>>      
>>>>> Nicholas Sterling wrote:
>>>>>
>>>>>
>>>>>        
>>>>>> Daniel Julin wrote:
>>>>>>
>>>>>>
>>>>>>          
>>>>>>> I like that approach a lot, because it may also address the other
>>>>>>>             
>> concern
>>  
>>>>>>> that a proposed "default reasonable behavior" may not be 
>>>>>>> appropriate
>>>>>>>             
>> for
>>  
>>>>>>> all usage scenarios. We could probably come-up with a variety of
>>>>>>>             
>> handlers
>>  
>>>>>>> for various common behaviors, like printing a simple error message,
>>>>>>> completely ignoring the error, and lots of other creative 
>>>>>>> responses.
>>>>>>>
>>>>>>> Incidentally, nothing in this discussion is particularly 
>>>>>>> specific to
>>>>>>>             
>> the
>>  
>>>>>>> Kato API, is it? Are we saying that, in general, we don't like
>>>>>>>             
>> exceptions
>>  
>>>>>>> as the standard mechanism to report errors in Java, and that we're
>>>>>>> inventing new patterns?  If so, have any useful patterns been
>>>>>>>             
>> proposed
>>  
>>>>>>> and
>>>>>>> documented previously in the literature?
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>             
>>>>>> I just looked around a little, and am only seeing suggestions for 
>>>>>> how
>>>>>>           
>> the
>>  
>>>>>> *client* can abstract out the exception-handling logic using the
>>>>>>           
>> Template
>>  
>>>>>> design pattern.  So far I haven't seen any advice for API designers.
>>>>>>
>>>>>> By the way, it occurred to me that the setter can have a generic 
>>>>>> name
>>>>>> because overloading will allow us to have a method for each
>>>>>>           
>> condition:
>>  
>>>>>>   factory.setHandler( new DataUnavailableHandler( ... ) {
>>>>>>       ...
>>>>>>   } );
>>>>>>
>>>>>> Also, it might make sense to push the handler on a stack rather
>>>>>>           
>> replace
>>  
>>>>>> what is there.  That will allow independent modules to modify just
>>>>>>           
>> that
>>  
>>>>>> behavior they need to and then remove those modifications when they
>>>>>>           
>> are no
>>  
>>>>>> longer needed.  It also means that we can have just one Handler
>>>>>>           
>>> () class for
>>>    
>>>>>> all the handlers, e.g.
>>>>>>
>>>>>>   // Temporarily override the handling of DataUnavailable errors.
>>>>>>   factory.pushHandler( new Handler( ... ) {
>>>>>>       void handleJavaObjectUnavailable(...) {
>>>>>>           // handling specific for JavaObjects
>>>>>>       }
>>>>>>       void handleDataUnavailable(...) {
>>>>>>           // handling for all other DataUnavailable conditions
>>>>>>       }
>>>>>>       // All handler methods not overridden will simply call the 
>>>>>> same
>>>>>> method
>>>>>>       // for the object beneath us on the stack.  If we get to the
>>>>>>           
>> bottom,
>>  
>>>>>> the
>>>>>>       // handler there will throw an exception.
>>>>>>   } );
>>>>>>   // Do some work that might cause an exception.  This might include
>>>>>> calling
>>>>>>   // an independently written module that also wants to temporarily
>>>>>> override
>>>>>>   // some handler, but they will pop that before returning to us.
>>>>>>   factory.popHandler();
>>>>>>
>>>>>> Nicholas
>>>>>>
>>>>>>
>>>>>>
>>>>>>          
>>>>>>> -- Daniel --,
>>>>>>>
>>>>>>>
>>>>>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-11 01:48:53 AM:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>            
>>>>>>>> Daniel Julin wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>              
>>>>>>>>> I guess a two mode approach would make everyone happy. But would
>>>>>>>>>                 
>> it
>>  
>>>>>>>>>
>>>>>>>>>                 
>>>>>>>> make
>>>>>>>>
>>>>>>>>               the API too complicated?
>>>>>>>>
>>>>>>>>              
>>>>>>>>>
>>>>>>>>>                 
>>>>>>>> I have some sympathy for what Steve is talking about -- maybe my
>>>>>>>> short-term memory is small, but when lots of single lines of code
>>>>>>>> inflate to 6 lines (and two indentation levels), it is definitely
>>>>>>>>               
>> harder
>>  
>>>>>>>> for me to read.  However, I wouldn't want to give up the certain
>>>>>>>>               
>> and
>>  
>>>>>>>> immediate catching of errors offered by exceptions.
>>>>>>>>
>>>>>>>> Would a mechanism like this work for the two-mode approach?
>>>>>>>>
>>>>>>>>    factory.setDataUnavailableHandler( new DataUnavailableHandler
>>>>>>>>               
>> ( ... )
>>  
>>>>>>>>
>>>>>>>>               
>>>>>>> {
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>            
>>>>>>>>        ...
>>>>>>>>    } );
>>>>>>>>
>>>>>>>> All objects created by the factory would call that object's
>>>>>>>> dataUnavailable() method when appropriate, passing it enough info
>>>>>>>>               
>> about
>>  
>>>>>>>> what was going on to allow the method to make interesting 
>>>>>>>> decisions
>>>>>>>> about what to do.  The default handler would always throw a
>>>>>>>> DataUnavailableException.
>>>>>>>>
>>>>>>>> It's hard for me to tell whether something like that would really
>>>>>>>> suffice in actual use.  Perhaps it would have to be finer-grained,
>>>>>>>>               
>> with
>>  
>>>>>>>> methods for javaObjectUnavailable(), imageSectionUnavailable(),
>>>>>>>>               
>> etc.
>>  
>>>>>>>> Perhaps the defaults for those would call the more generic
>>>>>>>> dataUnavailable() so that you could intervene for all cases and/or
>>>>>>>>               
>> for
>>  
>>>>>>>> individual cases as desired.
>>>>>>>>
>>>>>>>> Nicholas
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>               
>>>>>>>             
>>>>       
>>
>>   
>

Re: Kato API javadoc - error handling

Posted by Nicholas Sterling <Ni...@Sun.COM>.
That last example, the JDBC sanitizer, is much more conventional -- 
there's no handler stack.  It is essentially a combination of the 
Template and Visitor design patterns.  The Template pattern is often 
applied to Java exceptions, so I don't think this would be thought of as 
unusual.

Instance variables in the anonymous class would be accessible to both 
the method doing the work and the method handling the exceptions.  And 
the class could access final variables outside it:

    final Foo outside_class = ...;

    HeapVisitor visitor = new HeapVisitor() {

        Foo inside_class = ...;

        void visitObject( JavaObject obj ) {
            // Both outside_class and inside_class are visible.
            // Var outside_class cannot be modified, of course,
            // but fields in the object it refers to may.
        }

        void handleDataUnavailable( JavaObject obj ) {
            // Same here.
            // If we didn't put this method here, the default
            // would just throw a DataUnavailableException.
        }
    };

    JavaHeap heap = factory.getJavaHeap(...);
    heap.visit( visitor );

Does something like that seem reasonable?

Nicholas



Daniel Julin wrote:
> It seems to me that with all this discussion of polymorphic and stackable
> error handlers, we're rapidly re-inventing much of the Java exception
> facility, and probably rediscovering a lot of the same design
> considerations that the original designers of that Java exception facility
> faced...
>
> As far as I can tell, the one major difference is that, with Java
> exceptions, once an exception is thrown, the flow of control is irrevocably
> interrupted and can only resume after the exception handler, not back at
> the point where the exception was thrown. This means that if you do want
> fine control over your errors but don't want to interrupt a whole sequence
> of operations, you're forced to put an explicit try/catch block at every
> line of the program. Whereas with these proposed handlers, a single
> top-level handler could presumably take care of all the errors in a
> sequence of operations without interrupting that sequence.
>
> Is that a correct interpretation? And is there no practical way to achieve
> the same effect with actual Java exceptions? Some sort of "continue"
> statement inside a catch block, maybe?
>
>
> On the other hand, one thing that Java try/catch blocks offer is controlled
> access to the local variables of the method in which the try/catch block
> resides, and to the private instance members of the object. The proposed
> handlers, since they are executing in a separate object and a separate
> method, would not enjoy a similar access. Whether this limitation would
> prove bothersome in practice, will depend on the actual usage scenarios
> that we face...
>
>
> -- Daniel --
>
>
>
> Nicholas.Sterling@Sun.COM wrote on 2009-04-14 05:39:40 PM:
>   
>> If we were to end up doing something like this, would we use checked or
>> unchecked exceptions?  If we use checked exceptions, the client will
>> still have to catch the exception or say that the method throws it.
>> Presumably that would defeat the purpose...
>>
>> Good idea on the comparison code.  I'm a little concerned that people
>> may think we are overengineering the whole exception thing; once we have
>> the comparison code, we can run it by some folks and see whether their
>> brains short-circuit.
>>
>> It might be helpful as a reference point to consider an example with
>> another API.  I was sufficiently frustrated by the unreadability of my
>> JDBC clients that I wrote a pair of classes, Query and Querier, that
>> hide gory details, and I think it makes a big difference.  Among the
>> hidden are the binding of variables and iterating through result sets,
>> but probably the biggest benefit is from hiding the exception-handling
>> logic (it closes the ResultSet for you on an exception). This is what it
>> looks like to use it:
>>
>>     // Create a query to get recent bugs.
>>     static final Query recent_bugs_query = new Query(
>>         "bugs submitted against a PRODUCT in the last NUM DAYS",
>>         "select id, synopsis from bugs " +
>>        " where product = ? and date_submitted > sysdate - ?"
>>     );
>>     ...
>>     // Given a Connection conn and values for PRODUCT and NUM DAYS,
>>     // query the DB for recent bugs and display the resulting rows.
>>     new Querier( recent_bugs_query, conn, product, num_days ) {
>>         public void doRow() throws SQLException {
>>             System.out.println( rs.getString(1) + " " + rs.getString
>>     
> (2) );
>   
>>         }
>>     }
>>
>> A major benefit was getting rid of that awful doubly-nested catch block
>> (closing the ResultSet in the catch block may throw an exception, so it
>> requires its own try-catch -- gaah!).
>>
>> The default Querier throws an exception, but you can extend Querier and
>> override the handleException() method to do whatever is appropriate for
>> your app, and they use your custom Querier throughout your program, e.g.
>>
>>     class MyQuerier extends Querier {
>>         void handleException( Exception ex ) {
>>             ....
>>         }
>>     }
>>
>> Perhaps we could use a similar approach, for example providing a
>> HeapQuerier class from which clients create anonymous classes to do what
>> they want.
>>
>> Nicholas
>>
>>
>>
>> Steve Poole wrote:
>>     
>>> On Mon, Apr 13, 2009 at 4:34 AM, Nicholas Sterling <
>>> Nicholas.Sterling@sun.com> wrote:
>>>
>>>
>>>       
>>>> And a Handler (whatever it should really be called) would have access
>>>>         
> to
>   
>>>> the previous Handler on the stack, so it could do
>>>>
>>>>   void handleJavaObjectUnavailable(...) {
>>>>       // do some stuff, then defer to the guy beneath us on the stack:
>>>>       prevHandler().handleJavaObjectUnavailable(...);
>>>>   }
>>>> Nicholas
>>>>
>>>> This is cool -  The callback approach is sort of a half way
>>>>         
> housebetween a
>   
>>> DOM and SAX model.  It could allow us to have a default "no nulls"
>>>       
> approch
>   
>>> for an implementation but still allows for users of the API to do
>>>       
> something
>   
>>> different.
>>>
>>> I think we should create some comparison code segments to see what it
>>>       
> could
>   
>>> look like.
>>>
>>>
>>>       
>>>> Nicholas Sterling wrote:
>>>>
>>>>
>>>>         
>>>>> Daniel Julin wrote:
>>>>>
>>>>>
>>>>>           
>>>>>> I like that approach a lot, because it may also address the other
>>>>>>             
> concern
>   
>>>>>> that a proposed "default reasonable behavior" may not be appropriate
>>>>>>             
> for
>   
>>>>>> all usage scenarios. We could probably come-up with a variety of
>>>>>>             
> handlers
>   
>>>>>> for various common behaviors, like printing a simple error message,
>>>>>> completely ignoring the error, and lots of other creative responses.
>>>>>>
>>>>>> Incidentally, nothing in this discussion is particularly specific to
>>>>>>             
> the
>   
>>>>>> Kato API, is it? Are we saying that, in general, we don't like
>>>>>>             
> exceptions
>   
>>>>>> as the standard mechanism to report errors in Java, and that we're
>>>>>> inventing new patterns?  If so, have any useful patterns been
>>>>>>             
> proposed
>   
>>>>>> and
>>>>>> documented previously in the literature?
>>>>>>
>>>>>>
>>>>>>
>>>>>>             
>>>>> I just looked around a little, and am only seeing suggestions for how
>>>>>           
> the
>   
>>>>> *client* can abstract out the exception-handling logic using the
>>>>>           
> Template
>   
>>>>> design pattern.  So far I haven't seen any advice for API designers.
>>>>>
>>>>> By the way, it occurred to me that the setter can have a generic name
>>>>> because overloading will allow us to have a method for each
>>>>>           
> condition:
>   
>>>>>   factory.setHandler( new DataUnavailableHandler( ... ) {
>>>>>       ...
>>>>>   } );
>>>>>
>>>>> Also, it might make sense to push the handler on a stack rather
>>>>>           
> replace
>   
>>>>> what is there.  That will allow independent modules to modify just
>>>>>           
> that
>   
>>>>> behavior they need to and then remove those modifications when they
>>>>>           
> are no
>   
>>>>> longer needed.  It also means that we can have just one Handler
>>>>>           
>> () class for
>>     
>>>>> all the handlers, e.g.
>>>>>
>>>>>   // Temporarily override the handling of DataUnavailable errors.
>>>>>   factory.pushHandler( new Handler( ... ) {
>>>>>       void handleJavaObjectUnavailable(...) {
>>>>>           // handling specific for JavaObjects
>>>>>       }
>>>>>       void handleDataUnavailable(...) {
>>>>>           // handling for all other DataUnavailable conditions
>>>>>       }
>>>>>       // All handler methods not overridden will simply call the same
>>>>> method
>>>>>       // for the object beneath us on the stack.  If we get to the
>>>>>           
> bottom,
>   
>>>>> the
>>>>>       // handler there will throw an exception.
>>>>>   } );
>>>>>   // Do some work that might cause an exception.  This might include
>>>>> calling
>>>>>   // an independently written module that also wants to temporarily
>>>>> override
>>>>>   // some handler, but they will pop that before returning to us.
>>>>>   factory.popHandler();
>>>>>
>>>>> Nicholas
>>>>>
>>>>>
>>>>>
>>>>>           
>>>>>> -- Daniel --,
>>>>>>
>>>>>>
>>>>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-11 01:48:53 AM:
>>>>>>
>>>>>>
>>>>>>
>>>>>>             
>>>>>>> Daniel Julin wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>               
>>>>>>>> I guess a two mode approach would make everyone happy. But would
>>>>>>>>                 
> it
>   
>>>>>>>>
>>>>>>>>                 
>>>>>>> make
>>>>>>>
>>>>>>>               
>>>>>>> the API too complicated?
>>>>>>>
>>>>>>>               
>>>>>>>>
>>>>>>>>                 
>>>>>>> I have some sympathy for what Steve is talking about -- maybe my
>>>>>>> short-term memory is small, but when lots of single lines of code
>>>>>>> inflate to 6 lines (and two indentation levels), it is definitely
>>>>>>>               
> harder
>   
>>>>>>> for me to read.  However, I wouldn't want to give up the certain
>>>>>>>               
> and
>   
>>>>>>> immediate catching of errors offered by exceptions.
>>>>>>>
>>>>>>> Would a mechanism like this work for the two-mode approach?
>>>>>>>
>>>>>>>    factory.setDataUnavailableHandler( new DataUnavailableHandler
>>>>>>>               
> ( ... )
>   
>>>>>>>
>>>>>>>               
>>>>>> {
>>>>>>
>>>>>>
>>>>>>
>>>>>>             
>>>>>>>        ...
>>>>>>>    } );
>>>>>>>
>>>>>>> All objects created by the factory would call that object's
>>>>>>> dataUnavailable() method when appropriate, passing it enough info
>>>>>>>               
> about
>   
>>>>>>> what was going on to allow the method to make interesting decisions
>>>>>>> about what to do.  The default handler would always throw a
>>>>>>> DataUnavailableException.
>>>>>>>
>>>>>>> It's hard for me to tell whether something like that would really
>>>>>>> suffice in actual use.  Perhaps it would have to be finer-grained,
>>>>>>>               
> with
>   
>>>>>>> methods for javaObjectUnavailable(), imageSectionUnavailable(),
>>>>>>>               
> etc.
>   
>>>>>>> Perhaps the defaults for those would call the more generic
>>>>>>> dataUnavailable() so that you could intervene for all cases and/or
>>>>>>>               
> for
>   
>>>>>>> individual cases as desired.
>>>>>>>
>>>>>>> Nicholas
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>               
>>>>>>             
>>>       
>
>   

Re: Kato API javadoc - error handling

Posted by Daniel Julin <dp...@us.ibm.com>.
It seems to me that with all this discussion of polymorphic and stackable
error handlers, we're rapidly re-inventing much of the Java exception
facility, and probably rediscovering a lot of the same design
considerations that the original designers of that Java exception facility
faced...

As far as I can tell, the one major difference is that, with Java
exceptions, once an exception is thrown, the flow of control is irrevocably
interrupted and can only resume after the exception handler, not back at
the point where the exception was thrown. This means that if you do want
fine control over your errors but don't want to interrupt a whole sequence
of operations, you're forced to put an explicit try/catch block at every
line of the program. Whereas with these proposed handlers, a single
top-level handler could presumably take care of all the errors in a
sequence of operations without interrupting that sequence.

Is that a correct interpretation? And is there no practical way to achieve
the same effect with actual Java exceptions? Some sort of "continue"
statement inside a catch block, maybe?


On the other hand, one thing that Java try/catch blocks offer is controlled
access to the local variables of the method in which the try/catch block
resides, and to the private instance members of the object. The proposed
handlers, since they are executing in a separate object and a separate
method, would not enjoy a similar access. Whether this limitation would
prove bothersome in practice, will depend on the actual usage scenarios
that we face...


-- Daniel --



Nicholas.Sterling@Sun.COM wrote on 2009-04-14 05:39:40 PM:
> If we were to end up doing something like this, would we use checked or
> unchecked exceptions?  If we use checked exceptions, the client will
> still have to catch the exception or say that the method throws it.
> Presumably that would defeat the purpose...
>
> Good idea on the comparison code.  I'm a little concerned that people
> may think we are overengineering the whole exception thing; once we have
> the comparison code, we can run it by some folks and see whether their
> brains short-circuit.
>
> It might be helpful as a reference point to consider an example with
> another API.  I was sufficiently frustrated by the unreadability of my
> JDBC clients that I wrote a pair of classes, Query and Querier, that
> hide gory details, and I think it makes a big difference.  Among the
> hidden are the binding of variables and iterating through result sets,
> but probably the biggest benefit is from hiding the exception-handling
> logic (it closes the ResultSet for you on an exception). This is what it
> looks like to use it:
>
>     // Create a query to get recent bugs.
>     static final Query recent_bugs_query = new Query(
>         "bugs submitted against a PRODUCT in the last NUM DAYS",
>         "select id, synopsis from bugs " +
>        " where product = ? and date_submitted > sysdate - ?"
>     );
>     ...
>     // Given a Connection conn and values for PRODUCT and NUM DAYS,
>     // query the DB for recent bugs and display the resulting rows.
>     new Querier( recent_bugs_query, conn, product, num_days ) {
>         public void doRow() throws SQLException {
>             System.out.println( rs.getString(1) + " " + rs.getString
(2) );
>         }
>     }
>
> A major benefit was getting rid of that awful doubly-nested catch block
> (closing the ResultSet in the catch block may throw an exception, so it
> requires its own try-catch -- gaah!).
>
> The default Querier throws an exception, but you can extend Querier and
> override the handleException() method to do whatever is appropriate for
> your app, and they use your custom Querier throughout your program, e.g.
>
>     class MyQuerier extends Querier {
>         void handleException( Exception ex ) {
>             ....
>         }
>     }
>
> Perhaps we could use a similar approach, for example providing a
> HeapQuerier class from which clients create anonymous classes to do what
> they want.
>
> Nicholas
>
>
>
> Steve Poole wrote:
> > On Mon, Apr 13, 2009 at 4:34 AM, Nicholas Sterling <
> > Nicholas.Sterling@sun.com> wrote:
> >
> >
> >> And a Handler (whatever it should really be called) would have access
to
> >> the previous Handler on the stack, so it could do
> >>
> >>   void handleJavaObjectUnavailable(...) {
> >>       // do some stuff, then defer to the guy beneath us on the stack:
> >>       prevHandler().handleJavaObjectUnavailable(...);
> >>   }
> >> Nicholas
> >>
> >> This is cool -  The callback approach is sort of a half way
housebetween a
> >>
> > DOM and SAX model.  It could allow us to have a default "no nulls"
approch
> > for an implementation but still allows for users of the API to do
something
> > different.
> >
> > I think we should create some comparison code segments to see what it
could
> > look like.
> >
> >
> >> Nicholas Sterling wrote:
> >>
> >>
> >>> Daniel Julin wrote:
> >>>
> >>>
> >>>> I like that approach a lot, because it may also address the other
concern
> >>>> that a proposed "default reasonable behavior" may not be appropriate
for
> >>>> all usage scenarios. We could probably come-up with a variety of
handlers
> >>>> for various common behaviors, like printing a simple error message,
> >>>> completely ignoring the error, and lots of other creative responses.
> >>>>
> >>>> Incidentally, nothing in this discussion is particularly specific to
the
> >>>> Kato API, is it? Are we saying that, in general, we don't like
exceptions
> >>>> as the standard mechanism to report errors in Java, and that we're
> >>>> inventing new patterns?  If so, have any useful patterns been
proposed
> >>>> and
> >>>> documented previously in the literature?
> >>>>
> >>>>
> >>>>
> >>> I just looked around a little, and am only seeing suggestions for how
the
> >>> *client* can abstract out the exception-handling logic using the
Template
> >>> design pattern.  So far I haven't seen any advice for API designers.
> >>>
> >>> By the way, it occurred to me that the setter can have a generic name
> >>> because overloading will allow us to have a method for each
condition:
> >>>
> >>>   factory.setHandler( new DataUnavailableHandler( ... ) {
> >>>       ...
> >>>   } );
> >>>
> >>> Also, it might make sense to push the handler on a stack rather
replace
> >>> what is there.  That will allow independent modules to modify just
that
> >>> behavior they need to and then remove those modifications when they
are no
> >>> longer needed.  It also means that we can have just one Handler
> () class for
> >>> all the handlers, e.g.
> >>>
> >>>   // Temporarily override the handling of DataUnavailable errors.
> >>>   factory.pushHandler( new Handler( ... ) {
> >>>       void handleJavaObjectUnavailable(...) {
> >>>           // handling specific for JavaObjects
> >>>       }
> >>>       void handleDataUnavailable(...) {
> >>>           // handling for all other DataUnavailable conditions
> >>>       }
> >>>       // All handler methods not overridden will simply call the same
> >>> method
> >>>       // for the object beneath us on the stack.  If we get to the
bottom,
> >>> the
> >>>       // handler there will throw an exception.
> >>>   } );
> >>>   // Do some work that might cause an exception.  This might include
> >>> calling
> >>>   // an independently written module that also wants to temporarily
> >>> override
> >>>   // some handler, but they will pop that before returning to us.
> >>>   factory.popHandler();
> >>>
> >>> Nicholas
> >>>
> >>>
> >>>
> >>>> -- Daniel --,
> >>>>
> >>>>
> >>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-11 01:48:53 AM:
> >>>>
> >>>>
> >>>>
> >>>>> Daniel Julin wrote:
> >>>>>
> >>>>>
> >>>>>
> >>>>>> I guess a two mode approach would make everyone happy. But would
it
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>> make
> >>>>>
> >>>>
> >>>>> the API too complicated?
> >>>>>
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>> I have some sympathy for what Steve is talking about -- maybe my
> >>>>> short-term memory is small, but when lots of single lines of code
> >>>>> inflate to 6 lines (and two indentation levels), it is definitely
harder
> >>>>> for me to read.  However, I wouldn't want to give up the certain
and
> >>>>> immediate catching of errors offered by exceptions.
> >>>>>
> >>>>> Would a mechanism like this work for the two-mode approach?
> >>>>>
> >>>>>    factory.setDataUnavailableHandler( new DataUnavailableHandler
( ... )
> >>>>>
> >>>>>
> >>>>>
> >>>> {
> >>>>
> >>>>
> >>>>
> >>>>>        ...
> >>>>>    } );
> >>>>>
> >>>>> All objects created by the factory would call that object's
> >>>>> dataUnavailable() method when appropriate, passing it enough info
about
> >>>>> what was going on to allow the method to make interesting decisions
> >>>>> about what to do.  The default handler would always throw a
> >>>>> DataUnavailableException.
> >>>>>
> >>>>> It's hard for me to tell whether something like that would really
> >>>>> suffice in actual use.  Perhaps it would have to be finer-grained,
with
> >>>>> methods for javaObjectUnavailable(), imageSectionUnavailable(),
etc.
> >>>>> Perhaps the defaults for those would call the more generic
> >>>>> dataUnavailable() so that you could intervene for all cases and/or
for
> >>>>> individual cases as desired.
> >>>>>
> >>>>> Nicholas
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>
> >>>>
> >>>
> >
> >

Re: Kato API javadoc - error handling

Posted by Nicholas Sterling <Ni...@Sun.COM>.
If we were to end up doing something like this, would we use checked or 
unchecked exceptions?  If we use checked exceptions, the client will 
still have to catch the exception or say that the method throws it.  
Presumably that would defeat the purpose...

Good idea on the comparison code.  I'm a little concerned that people 
may think we are overengineering the whole exception thing; once we have 
the comparison code, we can run it by some folks and see whether their 
brains short-circuit.

It might be helpful as a reference point to consider an example with 
another API.  I was sufficiently frustrated by the unreadability of my 
JDBC clients that I wrote a pair of classes, Query and Querier, that 
hide gory details, and I think it makes a big difference.  Among the 
hidden are the binding of variables and iterating through result sets, 
but probably the biggest benefit is from hiding the exception-handling 
logic (it closes the ResultSet for you on an exception). This is what it 
looks like to use it:

    // Create a query to get recent bugs.
    static final Query recent_bugs_query = new Query(
        "bugs submitted against a PRODUCT in the last NUM DAYS",
        "select id, synopsis from bugs " +
       " where product = ? and date_submitted > sysdate - ?"
    );
    ...
    // Given a Connection conn and values for PRODUCT and NUM DAYS,
    // query the DB for recent bugs and display the resulting rows.
    new Querier( recent_bugs_query, conn, product, num_days ) {
        public void doRow() throws SQLException {
            System.out.println( rs.getString(1) + " " + rs.getString(2) );
        }
    }

A major benefit was getting rid of that awful doubly-nested catch block 
(closing the ResultSet in the catch block may throw an exception, so it 
requires its own try-catch -- gaah!).

The default Querier throws an exception, but you can extend Querier and 
override the handleException() method to do whatever is appropriate for 
your app, and they use your custom Querier throughout your program, e.g.

    class MyQuerier extends Querier {
        void handleException( Exception ex ) {
            ....
        }
    }

Perhaps we could use a similar approach, for example providing a 
HeapQuerier class from which clients create anonymous classes to do what 
they want.

Nicholas



Steve Poole wrote:
> On Mon, Apr 13, 2009 at 4:34 AM, Nicholas Sterling <
> Nicholas.Sterling@sun.com> wrote:
>
>   
>> And a Handler (whatever it should really be called) would have access to
>> the previous Handler on the stack, so it could do
>>
>>   void handleJavaObjectUnavailable(...) {
>>       // do some stuff, then defer to the guy beneath us on the stack:
>>       prevHandler().handleJavaObjectUnavailable(...);
>>   }
>> Nicholas
>>
>> This is cool -  The callback approach is sort of a half way house between a
>>     
> DOM and SAX model.  It could allow us to have a default "no nulls" approch
> for an implementation but still allows for users of the API to do something
> different.
>
> I think we should create some comparison code segments to see what it could
> look like.
>
>   
>> Nicholas Sterling wrote:
>>
>>     
>>> Daniel Julin wrote:
>>>
>>>       
>>>> I like that approach a lot, because it may also address the other concern
>>>> that a proposed "default reasonable behavior" may not be appropriate for
>>>> all usage scenarios. We could probably come-up with a variety of handlers
>>>> for various common behaviors, like printing a simple error message,
>>>> completely ignoring the error, and lots of other creative responses.
>>>>
>>>> Incidentally, nothing in this discussion is particularly specific to the
>>>> Kato API, is it? Are we saying that, in general, we don't like exceptions
>>>> as the standard mechanism to report errors in Java, and that we're
>>>> inventing new patterns?  If so, have any useful patterns been proposed
>>>> and
>>>> documented previously in the literature?
>>>>
>>>>
>>>>         
>>> I just looked around a little, and am only seeing suggestions for how the
>>> *client* can abstract out the exception-handling logic using the Template
>>> design pattern.  So far I haven't seen any advice for API designers.
>>>
>>> By the way, it occurred to me that the setter can have a generic name
>>> because overloading will allow us to have a method for each condition:
>>>
>>>   factory.setHandler( new DataUnavailableHandler( ... ) {
>>>       ...
>>>   } );
>>>
>>> Also, it might make sense to push the handler on a stack rather replace
>>> what is there.  That will allow independent modules to modify just that
>>> behavior they need to and then remove those modifications when they are no
>>> longer needed.  It also means that we can have just one Handler() class for
>>> all the handlers, e.g.
>>>
>>>   // Temporarily override the handling of DataUnavailable errors.
>>>   factory.pushHandler( new Handler( ... ) {
>>>       void handleJavaObjectUnavailable(...) {
>>>           // handling specific for JavaObjects
>>>       }
>>>       void handleDataUnavailable(...) {
>>>           // handling for all other DataUnavailable conditions
>>>       }
>>>       // All handler methods not overridden will simply call the same
>>> method
>>>       // for the object beneath us on the stack.  If we get to the bottom,
>>> the
>>>       // handler there will throw an exception.
>>>   } );
>>>   // Do some work that might cause an exception.  This might include
>>> calling
>>>   // an independently written module that also wants to temporarily
>>> override
>>>   // some handler, but they will pop that before returning to us.
>>>   factory.popHandler();
>>>
>>> Nicholas
>>>
>>>
>>>       
>>>> -- Daniel --,
>>>>
>>>>
>>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-11 01:48:53 AM:
>>>>
>>>>
>>>>         
>>>>> Daniel Julin wrote:
>>>>>
>>>>>
>>>>>           
>>>>>> I guess a two mode approach would make everyone happy. But would it
>>>>>>
>>>>>>
>>>>>>             
>>>>> make
>>>>>           
>>>>         
>>>>> the API too complicated?
>>>>>           
>>>>>>
>>>>>>
>>>>>>             
>>>>> I have some sympathy for what Steve is talking about -- maybe my
>>>>> short-term memory is small, but when lots of single lines of code
>>>>> inflate to 6 lines (and two indentation levels), it is definitely harder
>>>>> for me to read.  However, I wouldn't want to give up the certain and
>>>>> immediate catching of errors offered by exceptions.
>>>>>
>>>>> Would a mechanism like this work for the two-mode approach?
>>>>>
>>>>>    factory.setDataUnavailableHandler( new DataUnavailableHandler( ... )
>>>>>
>>>>>
>>>>>           
>>>> {
>>>>
>>>>
>>>>         
>>>>>        ...
>>>>>    } );
>>>>>
>>>>> All objects created by the factory would call that object's
>>>>> dataUnavailable() method when appropriate, passing it enough info about
>>>>> what was going on to allow the method to make interesting decisions
>>>>> about what to do.  The default handler would always throw a
>>>>> DataUnavailableException.
>>>>>
>>>>> It's hard for me to tell whether something like that would really
>>>>> suffice in actual use.  Perhaps it would have to be finer-grained, with
>>>>> methods for javaObjectUnavailable(), imageSectionUnavailable(), etc.
>>>>> Perhaps the defaults for those would call the more generic
>>>>> dataUnavailable() so that you could intervene for all cases and/or for
>>>>> individual cases as desired.
>>>>>
>>>>> Nicholas
>>>>>
>>>>>
>>>>>
>>>>>           
>>>>
>>>>         
>>>       
>
>   

Re: Kato API javadoc - error handling

Posted by Steve Poole <sp...@googlemail.com>.
On Mon, Apr 13, 2009 at 4:34 AM, Nicholas Sterling <
Nicholas.Sterling@sun.com> wrote:

> And a Handler (whatever it should really be called) would have access to
> the previous Handler on the stack, so it could do
>
>   void handleJavaObjectUnavailable(...) {
>       // do some stuff, then defer to the guy beneath us on the stack:
>       prevHandler().handleJavaObjectUnavailable(...);
>   }
> Nicholas
>
> This is cool -  The callback approach is sort of a half way house between a
DOM and SAX model.  It could allow us to have a default "no nulls" approch
for an implementation but still allows for users of the API to do something
different.

I think we should create some comparison code segments to see what it could
look like.

>
>
> Nicholas Sterling wrote:
>
>>
>>
>> Daniel Julin wrote:
>>
>>> I like that approach a lot, because it may also address the other concern
>>> that a proposed "default reasonable behavior" may not be appropriate for
>>> all usage scenarios. We could probably come-up with a variety of handlers
>>> for various common behaviors, like printing a simple error message,
>>> completely ignoring the error, and lots of other creative responses.
>>>
>>> Incidentally, nothing in this discussion is particularly specific to the
>>> Kato API, is it? Are we saying that, in general, we don't like exceptions
>>> as the standard mechanism to report errors in Java, and that we're
>>> inventing new patterns?  If so, have any useful patterns been proposed
>>> and
>>> documented previously in the literature?
>>>
>>>
>> I just looked around a little, and am only seeing suggestions for how the
>> *client* can abstract out the exception-handling logic using the Template
>> design pattern.  So far I haven't seen any advice for API designers.
>>
>> By the way, it occurred to me that the setter can have a generic name
>> because overloading will allow us to have a method for each condition:
>>
>>   factory.setHandler( new DataUnavailableHandler( ... ) {
>>       ...
>>   } );
>>
>> Also, it might make sense to push the handler on a stack rather replace
>> what is there.  That will allow independent modules to modify just that
>> behavior they need to and then remove those modifications when they are no
>> longer needed.  It also means that we can have just one Handler() class for
>> all the handlers, e.g.
>>
>>   // Temporarily override the handling of DataUnavailable errors.
>>   factory.pushHandler( new Handler( ... ) {
>>       void handleJavaObjectUnavailable(...) {
>>           // handling specific for JavaObjects
>>       }
>>       void handleDataUnavailable(...) {
>>           // handling for all other DataUnavailable conditions
>>       }
>>       // All handler methods not overridden will simply call the same
>> method
>>       // for the object beneath us on the stack.  If we get to the bottom,
>> the
>>       // handler there will throw an exception.
>>   } );
>>   // Do some work that might cause an exception.  This might include
>> calling
>>   // an independently written module that also wants to temporarily
>> override
>>   // some handler, but they will pop that before returning to us.
>>   factory.popHandler();
>>
>> Nicholas
>>
>>
>>> -- Daniel --,
>>>
>>>
>>> Nicholas.Sterling@Sun.COM wrote on 2009-04-11 01:48:53 AM:
>>>
>>>
>>>> Daniel Julin wrote:
>>>>
>>>>
>>>>> I guess a two mode approach would make everyone happy. But would it
>>>>>
>>>>>
>>>> make
>>>
>>>
>>>> the API too complicated?
>>>>>
>>>>>
>>>>>
>>>>>
>>>> I have some sympathy for what Steve is talking about -- maybe my
>>>> short-term memory is small, but when lots of single lines of code
>>>> inflate to 6 lines (and two indentation levels), it is definitely harder
>>>> for me to read.  However, I wouldn't want to give up the certain and
>>>> immediate catching of errors offered by exceptions.
>>>>
>>>> Would a mechanism like this work for the two-mode approach?
>>>>
>>>>    factory.setDataUnavailableHandler( new DataUnavailableHandler( ... )
>>>>
>>>>
>>> {
>>>
>>>
>>>>        ...
>>>>    } );
>>>>
>>>> All objects created by the factory would call that object's
>>>> dataUnavailable() method when appropriate, passing it enough info about
>>>> what was going on to allow the method to make interesting decisions
>>>> about what to do.  The default handler would always throw a
>>>> DataUnavailableException.
>>>>
>>>> It's hard for me to tell whether something like that would really
>>>> suffice in actual use.  Perhaps it would have to be finer-grained, with
>>>> methods for javaObjectUnavailable(), imageSectionUnavailable(), etc.
>>>> Perhaps the defaults for those would call the more generic
>>>> dataUnavailable() so that you could intervene for all cases and/or for
>>>> individual cases as desired.
>>>>
>>>> Nicholas
>>>>
>>>>
>>>>
>>>
>>>
>>>
>>
>>

Re: Kato API javadoc - error handling

Posted by Nicholas Sterling <Ni...@Sun.COM>.
And a Handler (whatever it should really be called) would have access to 
the previous Handler on the stack, so it could do

    void handleJavaObjectUnavailable(...) {
        // do some stuff, then defer to the guy beneath us on the stack:
        prevHandler().handleJavaObjectUnavailable(...);
    } 

Nicholas


Nicholas Sterling wrote:
>
>
> Daniel Julin wrote:
>> I like that approach a lot, because it may also address the other 
>> concern
>> that a proposed "default reasonable behavior" may not be appropriate for
>> all usage scenarios. We could probably come-up with a variety of 
>> handlers
>> for various common behaviors, like printing a simple error message,
>> completely ignoring the error, and lots of other creative responses.
>>
>> Incidentally, nothing in this discussion is particularly specific to the
>> Kato API, is it? Are we saying that, in general, we don't like 
>> exceptions
>> as the standard mechanism to report errors in Java, and that we're
>> inventing new patterns?  If so, have any useful patterns been 
>> proposed and
>> documented previously in the literature?
>>   
> I just looked around a little, and am only seeing suggestions for how 
> the *client* can abstract out the exception-handling logic using the 
> Template design pattern.  So far I haven't seen any advice for API 
> designers.
>
> By the way, it occurred to me that the setter can have a generic name 
> because overloading will allow us to have a method for each condition:
>
>    factory.setHandler( new DataUnavailableHandler( ... ) {
>        ...
>    } );
>
> Also, it might make sense to push the handler on a stack rather 
> replace what is there.  That will allow independent modules to modify 
> just that behavior they need to and then remove those modifications 
> when they are no longer needed.  It also means that we can have just 
> one Handler() class for all the handlers, e.g.
>
>    // Temporarily override the handling of DataUnavailable errors.
>    factory.pushHandler( new Handler( ... ) {
>        void handleJavaObjectUnavailable(...) {
>            // handling specific for JavaObjects
>        }
>        void handleDataUnavailable(...) {
>            // handling for all other DataUnavailable conditions
>        }
>        // All handler methods not overridden will simply call the same 
> method
>        // for the object beneath us on the stack.  If we get to the 
> bottom, the
>        // handler there will throw an exception.
>    } );
>    // Do some work that might cause an exception.  This might include 
> calling
>    // an independently written module that also wants to temporarily 
> override
>    // some handler, but they will pop that before returning to us.
>    factory.popHandler();
>
> Nicholas
>
>>
>> -- Daniel --,
>>
>>
>> Nicholas.Sterling@Sun.COM wrote on 2009-04-11 01:48:53 AM:
>>  
>>> Daniel Julin wrote:
>>>    
>>>> I guess a two mode approach would make everyone happy. But would it
>>>>       
>> make
>>  
>>>> the API too complicated?
>>>>
>>>>
>>>>       
>>> I have some sympathy for what Steve is talking about -- maybe my
>>> short-term memory is small, but when lots of single lines of code
>>> inflate to 6 lines (and two indentation levels), it is definitely 
>>> harder
>>> for me to read.  However, I wouldn't want to give up the certain and
>>> immediate catching of errors offered by exceptions.
>>>
>>> Would a mechanism like this work for the two-mode approach?
>>>
>>>     factory.setDataUnavailableHandler( new DataUnavailableHandler( 
>>> ... )
>>>     
>> {
>>  
>>>         ...
>>>     } );
>>>
>>> All objects created by the factory would call that object's
>>> dataUnavailable() method when appropriate, passing it enough info about
>>> what was going on to allow the method to make interesting decisions
>>> about what to do.  The default handler would always throw a
>>> DataUnavailableException.
>>>
>>> It's hard for me to tell whether something like that would really
>>> suffice in actual use.  Perhaps it would have to be finer-grained, with
>>> methods for javaObjectUnavailable(), imageSectionUnavailable(), etc.
>>> Perhaps the defaults for those would call the more generic
>>> dataUnavailable() so that you could intervene for all cases and/or for
>>> individual cases as desired.
>>>
>>> Nicholas
>>>
>>>     
>>
>>   
>

Re: Kato API javadoc - error handling

Posted by Nicholas Sterling <Ni...@Sun.COM>.

Daniel Julin wrote:
> I like that approach a lot, because it may also address the other concern
> that a proposed "default reasonable behavior" may not be appropriate for
> all usage scenarios. We could probably come-up with a variety of handlers
> for various common behaviors, like printing a simple error message,
> completely ignoring the error, and lots of other creative responses.
>
> Incidentally, nothing in this discussion is particularly specific to the
> Kato API, is it? Are we saying that, in general, we don't like exceptions
> as the standard mechanism to report errors in Java, and that we're
> inventing new patterns?  If so, have any useful patterns been proposed and
> documented previously in the literature?
>   
I just looked around a little, and am only seeing suggestions for how 
the *client* can abstract out the exception-handling logic using the 
Template design pattern.  So far I haven't seen any advice for API 
designers.

By the way, it occurred to me that the setter can have a generic name 
because overloading will allow us to have a method for each condition:

    factory.setHandler( new DataUnavailableHandler( ... ) {
        ...
    } );

Also, it might make sense to push the handler on a stack rather replace 
what is there.  That will allow independent modules to modify just that 
behavior they need to and then remove those modifications when they are 
no longer needed.  It also means that we can have just one Handler() 
class for all the handlers, e.g.

    // Temporarily override the handling of DataUnavailable errors.
    factory.pushHandler( new Handler( ... ) {
        void handleJavaObjectUnavailable(...) {
            // handling specific for JavaObjects
        }
        void handleDataUnavailable(...) {
            // handling for all other DataUnavailable conditions
        }
        // All handler methods not overridden will simply call the same method
        // for the object beneath us on the stack.  If we get to the bottom, the
        // handler there will throw an exception.
    } );
    // Do some work that might cause an exception.  This might include calling
    // an independently written module that also wants to temporarily override
    // some handler, but they will pop that before returning to us.
    factory.popHandler();

Nicholas

>
> -- Daniel --,
>
>
> Nicholas.Sterling@Sun.COM wrote on 2009-04-11 01:48:53 AM:
>   
>> Daniel Julin wrote:
>>     
>>> I guess a two mode approach would make everyone happy. But would it
>>>       
> make
>   
>>> the API too complicated?
>>>
>>>
>>>       
>> I have some sympathy for what Steve is talking about -- maybe my
>> short-term memory is small, but when lots of single lines of code
>> inflate to 6 lines (and two indentation levels), it is definitely harder
>> for me to read.  However, I wouldn't want to give up the certain and
>> immediate catching of errors offered by exceptions.
>>
>> Would a mechanism like this work for the two-mode approach?
>>
>>     factory.setDataUnavailableHandler( new DataUnavailableHandler( ... )
>>     
> {
>   
>>         ...
>>     } );
>>
>> All objects created by the factory would call that object's
>> dataUnavailable() method when appropriate, passing it enough info about
>> what was going on to allow the method to make interesting decisions
>> about what to do.  The default handler would always throw a
>> DataUnavailableException.
>>
>> It's hard for me to tell whether something like that would really
>> suffice in actual use.  Perhaps it would have to be finer-grained, with
>> methods for javaObjectUnavailable(), imageSectionUnavailable(), etc.
>> Perhaps the defaults for those would call the more generic
>> dataUnavailable() so that you could intervene for all cases and/or for
>> individual cases as desired.
>>
>> Nicholas
>>
>>     
>
>   

Re: Kato API javadoc - error handling

Posted by Daniel Julin <dp...@us.ibm.com>.

I like that approach a lot, because it may also address the other concern
that a proposed "default reasonable behavior" may not be appropriate for
all usage scenarios. We could probably come-up with a variety of handlers
for various common behaviors, like printing a simple error message,
completely ignoring the error, and lots of other creative responses.

Incidentally, nothing in this discussion is particularly specific to the
Kato API, is it? Are we saying that, in general, we don't like exceptions
as the standard mechanism to report errors in Java, and that we're
inventing new patterns?  If so, have any useful patterns been proposed and
documented previously in the literature?


-- Daniel --,


Nicholas.Sterling@Sun.COM wrote on 2009-04-11 01:48:53 AM:
> Daniel Julin wrote:
> > I guess a two mode approach would make everyone happy. But would it
make
> > the API too complicated?
> >
> >
> I have some sympathy for what Steve is talking about -- maybe my
> short-term memory is small, but when lots of single lines of code
> inflate to 6 lines (and two indentation levels), it is definitely harder
> for me to read.  However, I wouldn't want to give up the certain and
> immediate catching of errors offered by exceptions.
>
> Would a mechanism like this work for the two-mode approach?
>
>     factory.setDataUnavailableHandler( new DataUnavailableHandler( ... )
{
>         ...
>     } );
>
> All objects created by the factory would call that object's
> dataUnavailable() method when appropriate, passing it enough info about
> what was going on to allow the method to make interesting decisions
> about what to do.  The default handler would always throw a
> DataUnavailableException.
>
> It's hard for me to tell whether something like that would really
> suffice in actual use.  Perhaps it would have to be finer-grained, with
> methods for javaObjectUnavailable(), imageSectionUnavailable(), etc.
> Perhaps the defaults for those would call the more generic
> dataUnavailable() so that you could intervene for all cases and/or for
> individual cases as desired.
>
> Nicholas
>

Re: Kato API javadoc - error handling

Posted by Nicholas Sterling <Ni...@Sun.COM>.

Daniel Julin wrote:
> I guess a two mode approach would make everyone happy. But would it make
> the API too complicated?
>
>   
I have some sympathy for what Steve is talking about -- maybe my 
short-term memory is small, but when lots of single lines of code 
inflate to 6 lines (and two indentation levels), it is definitely harder 
for me to read.  However, I wouldn't want to give up the certain and 
immediate catching of errors offered by exceptions.

Would a mechanism like this work for the two-mode approach?

    factory.setDataUnavailableHandler( new DataUnavailableHandler( ... ) {
        ...
    } );

All objects created by the factory would call that object's 
dataUnavailable() method when appropriate, passing it enough info about 
what was going on to allow the method to make interesting decisions 
about what to do.  The default handler would always throw a 
DataUnavailableException.

It's hard for me to tell whether something like that would really 
suffice in actual use.  Perhaps it would have to be finer-grained, with 
methods for javaObjectUnavailable(), imageSectionUnavailable(), etc.  
Perhaps the defaults for those would call the more generic 
dataUnavailable() so that you could intervene for all cases and/or for 
individual cases as desired.

Nicholas