Re: When and how to throw exceptions?

2010-04-10 Thread David Nicol
On Fri, Apr 9, 2010 at 1:54 AM, Ovid
publiustemp-moduleautho...@yahoo.comwrote:

 (Javaesque psuedo-code):

  try {
customer.read();
  }
  catch ( Exception::IO::NotFound e ) { ... }
  catch ( Exception::IO::CantOpen e ) { ... }
  catch ( Exception::IO::CantRead e ) { ... }
  catch ( Exception::IO   e ) { ... }
  catch ( Exception   e ) {
panic(I don't know what type of exception I have! . e);
  }

 Yeah, the example is overkill :)

 The point here is that you try more specific exceptions first and drill
 down to less specific ones, including a catch-all exception.  However,
 what happens if you get rid of the NotFound, CantOpen and CantRead? If
 the exception thrown is one of those types and assuming they're really
 subclasses of Exception::IO, then the Exception::IO catch will catch them
 rather the incorrectly falling through to the panic.  If these were merely
 shoved in a hash, you'd have to try to fall back to parsing either the
 messages (or the key) to figure out that you don't really have a panic.


I've never understood what's wrong with using string exceptions for this
kind of thing. Maintaining a discipline about properly dieing is required
both ways, and

 defined ($nextline = INPUT) or die IO CANTREAD: eof on INPUT?'

seems more concise than abstracting an exception type hierarchy behind a
class hierarchy only to unabstract it later:

  eval {
   $customer-read(); 1
 } or do {{  # double openers to create block to last out of
 my $e = $@;
 $e =~ m/^io notfound/i and do  { ...; last };
 $e =~ m/^io CantOpen/i and do { ... ; last };
 $e =~ m/^io CantRead/i and do { ... ; last };
 $e =~ m/^io /i and do { ... ; last };
die $e UNEXPECTED; # filename, line number, newline added by die
 }};

Either way, you still need to maintain the meaning of the string prefixes or
the various exception types in a project-wide data dictionary.

I don't want to start (or restart) some kind of big argument; my
understanding is that coders coming from a Java background simply prefer to
use classes for everything.


Re: When and how to throw exceptions?

2010-04-09 Thread Aristotle Pagaltzis
* Ovid publiustemp-moduleautho...@yahoo.com [2010-04-09 08:55]:
 Buut ... that's why you want those exceptions in classes
 instead of as hash keys.

Of course.

Just saying that if you *do* consider too many exception classes
a problem in need of a solution, then using a field as a message
selection key would at least preclude the need parse.

Regards,
-- 
Aristotle Pagaltzis // http://plasmasturm.org/


Re: When and how to throw exceptions?

2010-04-08 Thread Aristotle Pagaltzis
* Ovid publiustemp-moduleautho...@yahoo.com [2010-04-07 09:05]:
 Presumably the format should try to determine the number of
 conversions in the format and perhaps the alias could generate
 a sub with a corresponding prototype like 'sub
 throw_io_read($$)'. That might give you a touch of compile-time
 safety. Haven't really thought too carefully about this,
 though.

I think the best approach would be to tie String::Formatter into
Exception::Class, specifically its `require_named_input` and
`named_replace` options. To produce its message, an exception
class would pass its declared fields as format inputs. Then
resulting interface would look like this:

use Exception::Class (
'MyException',
'IOOpenRead' = {
isa= 'MyException',
alias  = 'throw_io_open',
fields = [ qw( file mode errno ) ],
format = 'Cannot open %{file} for %{mode}ing: %{errno}',
},
);

You’d use that like so:

open my $fh, '', $filename
or throw_io_open file = $filename, mode = 'read', errno = $!;

Regards,
-- 
Aristotle Pagaltzis // http://plasmasturm.org/


Re: When and how to throw exceptions?

2010-04-08 Thread Lutz Gehlen
Hi Ovid,

On Wed, Apr 07, 2010 at 12:04:08AM -0700, Ovid wrote:
 --- On Wed, 7/4/10, Lutz Gehlen lrg...@gmx.net wrote:
  What I need a central place for is the definition of the
  actual 
  error messages. With my module Exception::EasyThrow, I can
  write at 
  the beginning of my module:
  
  use Exception::EasyThrow
      (var_ud = 'Variable %s is undefined. We
  are doomed.',
       ... = ...);
  
  and then later
  
  var_ud('foo') if(!defined($foo));
 
 Note, in your code above, you can still have different error
 messages in different packages.  You've made things a touch easier,
 but not really solved the underlying problem.

I usually handle this by having a central module defining the error
functions and offering them for import.

  What about this proposal for Exception::Class?
 
   package My::Exceptions;
 
   use Exception::Class (
   'MyException',
   'IORead' = {
   isa= 'MyException',
   alias  = 'throw_io_read',
   format = [ 'Cannot open %s for reading: %s' ],
   },
   );
 
 And then:
 
   use My::Exceptions 'throw_io_read';
 
   open my $fh, '', $filename or throw_io_read $filename, $!;

I think that an inclusion into Exception::Class is definitely worth
thinking about. I even contacted Dave about it once, but I fear I
wasn't very clear about what I had in mind, so he suggested that I
publish my module first and he would consider it for
Exception::Class. Dave, what do you think about Ovid's suggestion?

One thing that always troubled me when I thought about a good way to
add my desired behaviour to Exception::Class and that is also an
issue with the 'format' suggestion is that I think that an own class
for each message might be a bit of an overkill. If I think of
exception hierarchies I rather think of a class like
My::Exception::IO (instead of IORead in your example). A read
failure would lead to an instance of the IO class with a message
about the read failure.

Therefore I went for a different way just for throwing the
exception. I don't claim to have made up my mind completely about
this. As mentioned before, I started this thread to raise a
discussion. But this is why I did not go your way so far.

Thanks for your comments,
Lutz


Re: When and how to throw exceptions?

2010-04-08 Thread Aristotle Pagaltzis
* Lutz Gehlen lrg...@gmx.net [2010-04-09 01:55]:
 I think that an own class for each message might be a bit of an
 overkill.

Why?

I guess that could be addressed by allowing a hash of formats and
then offering the throwing site to pick one of them by setting
a special field.

The key here is that you want to avoid a situation where catching
code has to parse the error message.

Regards,
-- 
Aristotle Pagaltzis // http://plasmasturm.org/


Re: When and how to throw exceptions?

2010-04-06 Thread Lutz Gehlen
Hi Aristotle,
sorry for the delayed reply, I had some computer problems and then 
this topic slipped a bit out of my mind.

On Friday 12 March 2010 23:33:40 Aristotle Pagaltzis wrote:
 * Lutz Gehlen lrg...@gmx.net [2010-02-21 01:40]:
  1) The first question deals with how to throw exceptions
  properly. In projects which ask for a more sophisticated way
  than just carping or croaking I use Exception::Class. However,
  in both cases the error message has to be assembled when the
  error is thrown.
 
 given that Exception::Class already provides a central place to
 define your exception hierarchy along with messages,… I don’t
 follow what it is that you need another central place for?

This might be one point where I don't understand how people use 
Exception::Class or how they throw exceptions at all. As I wrote in 
the original mail I might miss something here.

I understand that I can build a hierarchy of exception classes using 
Exception::Class. But when I throw an exception I still have to 
assemble the error message there, e.g.:

if(!defined($foo)) {
My::Exception::Class-throw
('Variable foo is undefined. We are doomed.');
}

As already shown by this simple example this is likely to span 
several lines thereby drawing unnecessary attention of the reader.
This is mitigated a little bit by the alias parameter of 
Exception::Class. However, if I don't pay close attention I might 
write somewhere else:

if(!defined($bar)) {
My::Exception::Class-throw
('We are doomed because variable bar is undefined.');
}

which is not how it should be. The same kind of error should produce 
the same message.
 
What I need a central place for is the definition of the actual 
error messages. With my module Exception::EasyThrow, I can write at 
the beginning of my module:

use Exception::EasyThrow
(var_ud = 'Variable %s is undefined. We are doomed.',
 ... = ...);

and then later

var_ud('foo') if(!defined($foo));

which is often possible in one line.
By default, it just croaks the message, but it can be set up to 
throw an Exception::Class object or do something else.

Do you see what I mean? Is this possible with Exception::Class 
alone? Or is it stupid for some reason to want this?

Thanks to everybody for advice
Lutz


Re: When and how to throw exceptions?

2010-03-12 Thread Aristotle Pagaltzis
Hi Lutz,

* Lutz Gehlen lrg...@gmx.net [2010-02-21 01:40]:
 1) The first question deals with how to throw exceptions
 properly. In projects which ask for a more sophisticated way
 than just carping or croaking I use Exception::Class. However,
 in both cases the error message has to be assembled when the
 error is thrown.

given that Exception::Class already provides a central place to
define your exception hierarchy along with messages,… I don’t
follow what it is that you need another central place for?

 2) My second question is how thorough I should be about
 throwing exceptions.

You don’t want to check each and every possibility. As you said,
if nothing else, it might needlessly prevent clever uses of your
code, and most of the time you don’t gain much anyway.

 My question is if there are any general guidelines how to
 decide what to check and what not (depending on my general
 security requirements) or do I have to perform some gut-feeling
 appraisal of efficiency vs. security?

There are basically two ways for errors to propagate: downward
and sideways.

• Downward propagation means you got something from the user, and
  you just passed it down through to something else without
  checking it.

  This is easy to debug: that’s what stack traces are for. Maybe
  the user passed something bad into your code and your code blew
  up. Then the error won’t be reported in their code, but a stack
  trace will tell them which call of theirs it was where they
  passed something nonsensical that caused your code to crash.

• Sideways propagation means you processed a value in some way,
  and then used or returned the result without checking if it’s
  good. Eg. first (try to) you turn a filename into a filehandle,
  then you blindly pass the filehandle to a function.

  This is hard to debug. The value that caused the problem is not
  a value passed down directly, it is the result of some
  computation whose intermediate states do not show up in the
  stack trace. The trace doesn’t tell you why that bad value got
  to be bad in the first place. You have to step through the code
  in a debugger or add print statements to track what happened.

I’m sure you can already imagine where this is going: basically,
you should check your own intermediate computed values, to ensure
you don’t propagate error conditions sideways between parts of
your own code. But if you operate on user input directly, and the
operation can blow up, you can leave that input unchecked for the
purposes of error reporting.

(You might of course still want to check it for other reasons, eg.
security. That’s a different matter.)

Regards,
-- 
Aristotle Pagaltzis // http://plasmasturm.org/


Re: When and how to throw exceptions?

2010-03-12 Thread Dave Rolsky

On Fri, 12 Mar 2010, Aristotle Pagaltzis wrote:


I’m sure you can already imagine where this is going: basically,
you should check your own intermediate computed values, to ensure
you don’t propagate error conditions sideways between parts of
your own code. But if you operate on user input directly, and the
operation can blow up, you can leave that input unchecked for the
purposes of error reporting.

(You might of course still want to check it for other reasons, eg.
security. That’s a different matter.)


Another good reason to check it is to provide a good error message. For 
example, division by zero at line 116 is much less useful than the foo 
parameter to the frabble() method must be a positive integer.



-dave

/*
http://VegGuide.org   http://blog.urth.org
Your guide to all that's veg  House Absolute(ly Pointless)
*/

Re: When and how to throw exceptions?

2010-02-21 Thread Daniel Staal
--As of February 21, 2010 1:43:58 PM +1300, Lutz Gehlen is alleged to have 
said:



Therefore I would like to define my error messages in some sprintf
format way at a central place and use these templates when the time
has come. I have written a module Exception::Class::EasyThrow that
does this. However, I still have not published it. The reason is
that I have the feeling that I don't know much about how to deal
with exceptions in general and I wonder: If everybody would have my
problem then there should be something on the CPAN already. And if
other people don't have my problem how do they deal with the issues
I have mentioned above? That's my first question.


Personally, I use a system somewhat like that, but I don't expect that 
class to be general.  If the point is that all exceptions are consistent in 
a project, I expect that class to be unique to the project.  (And I quite 
often won't make the messages themselves too detailed: The exception says 
where it was thrown, so I use that to track where the problem is.  The 
message is just for decoration if something were to get through to a user. 
It shouldn't be actually _used_ for anything.)



2) My second question is how thorough I should be about throwing
exceptions. Ideally, I would think that it should not only be
impossible that my module produces wrong results, but it should also
be impossible to trigger an internal Perl error within my module.
All the situations in which this would happen should be checked
beforehand and a proper exception should be thrown. However, this
goal raises several questions. To perform this thorough checks takes
a lot of development time and possibly also quite some execution
time. If I want to read in a long list of numbers, should I really
check that also the 3972nd one passes a looks_like_number test? In
general, should I really spend a lot of development and execution
time on checking input that no sane user would provide? On the other
hand, do I really want to claim to be able to anticipate every sane
scenario that a user might come up with?
Apart from that, is it really desirable to avoid internal perl
errors in any case? If Perl would die with Division by 0 is it
necessary to throw an exception a bit earlier which says Naughty
naughty! If I wouldn't have checked, perl would die with division by
0 in a moment.? However, what if perl bails out much later? Then
debugging might be much easier when the error is detected right
away.


Mostly, what you are likely think of as 'internal Perl errors' here _are_ 
exceptions, in a sense.  For instance, perl doesn't _die_ when it hits 
division by 0, it die()'s.  (Or some equivalent.)  If someone using your 
code is expecting exceptions and therefore calling your code in eval 
blocks, that will be caught.   (In other words: 'eval { say 1/0; } or say 
I had an error.;' will return 'I had an error.', not a 'Division by 0' 
error.)


So, basically, don't try to overdo it.  Perl will handle some things 
appropriately for you.  One of the basic rules I learned ages ago was 
'Don't test for a condition you aren't going to handle.'  Throw an 
exception if you expect the calling program to be able to handle the 
exception and recover in some way.  If that's not really possible, it's 
appropriate to die, and tell the user they're insane.  (Or, at least, that 
they've driven _you_ insane.)


Daniel T. Staal

---
This email copyright the author.  Unless otherwise noted, you
are expressly allowed to retransmit, quote, or otherwise use
the contents for non-commercial purposes.  This copyright will
expire 5 years after the author's death, or in 30 years,
whichever is longer, unless such a period is in excess of
local copyright law.
---