http://www.perlmonks.org?node_id=1017037

perlbaski has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to create exception class hierarchy. But I think I am not declaring them correctly as I am not able to refer to the exception objects.

use Exception::Class ( 'MyException', 'Commands' => { isa => 'MyException' }, 'Timeout' => { isa => 'Commands', description => 'These exceptions are resulted from running the metrics comm +ands' }, 'DBError' => { isa => 'MyException', description => 'DB returned error' } ); ThrowMyException(); sub ThrowMyException() { eval{MyException::Commands::Timeout->throw(error=>"This is error d +ue to timeout");}; my $err; if($err=Exception::Class->caught('MyException::Commands::Timeo +ut')){ #print Dumper($err); #print "err is of type ".ref($err); die $err->{"description"}.": ".$err->{"error"}; } elsif ( $err = Exception::Class->caught("MetricsException") ) +{ #print Dumper($err); die $err->error; } }

Can somebody see what is wrong with the code?

Replies are listed 'Best First'.
Re: Creating exception classes
by Athanasius (Archbishop) on Feb 05, 2013 at 02:35 UTC

    The problems are not in the declaration, but in sub ThrowMyException. Here is a working version, with changes commented:

    #! perl use strict; use warnings; use Exception::Class ( 'MyException', Commands => { isa => 'MyException', }, Timeout => { isa => 'Commands', description => 'This exception results from running the metric +s commands', }, DBError => { isa => 'MyException', description => 'DB returned error', }, ); ThrowMyException(); print "No error caught\n"; sub ThrowMyException # NO prototype { eval { Timeout->throw # NOT MyException::Commands::Timeo +ut-> ( error => "This error is due to a timeout" ); }; my $err; if ($err = Exception::Class->caught('Timeout')) { die $err->description . # NOT $err->{"description"} ': ' . $err->error; # NOT $err->{"error"} } elsif ($err = Exception::Class->caught('MetricsException')) { die $err->error; } else { $err = Exception::Class->caught(); ref $err ? $err->rethrow : die $err; } }

    Output:

    12:30 >perl 517_SoPW.pl This exception results from running the metrics commands: This error i +s due to a timeout at 517_SoPW.pl line 56. 12:33 >

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Thanks, that worked..I was thinking classes are blessed hashes, so I was trying to access them that way, looks like Exception::Class module creates accessors to access the fields. Am I correct?

        From the source code it appears that Exception::Class inherits from Exception::Class::Base. The documentation for Exception::Class::Base catalogues a number of class and/or object methods, among which are these:

        MyException->description()
        Returns the description for the given Exception::Class::Base subclass. ... This is also an object method.

        $exception->error()
        Returns the error/message associated with the exception.

        So these accessors are, as it were, “built-in” to any class derived from Exception::Class.

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Creating exception classes
by 7stud (Deacon) on Feb 05, 2013 at 02:42 UTC
    use strict; use warnings; use 5.012; use Exception::Class ( 'MyException', 'CommandException' => { isa => 'MyException' }, 'TimeoutException' => { isa => 'CommandException', description => 'This exception resulted from running the metrics commands' }, 'DBException' => { isa => 'MyException', description => 'DB returned error' } ); &ThrowMyException(); sub ThrowMyException() { eval{ TimeoutException->throw(error=>"This is error due to timeout +") }; my $err; if ($err = Exception::Class->caught('TimeoutException') ) { #print Dumper($err); #print "err is of type ".ref($err); die $err->description . ": " . $err->error; } elsif ( $err = Exception::Class->caught("MetricsException") ) { #print Dumper($err); die $err->error; } }

    If you see class names like A::B::C, that means the class is named C and it can be found in the directory A/B/. The A::B:: part is a namespace name to prevent name conflicts, but it also indicates the directory structure where the class is located. When you write A::B::C in your program, perl searches all the directories in @INC for a directory named A that has a subdirectory named B, which contains a file called C.pm.

      "When you write A::B::C in your program, perl searches all the directories in @INC for a directory named A that has a subdirectory named B, which contains a file called C.pm."

      No it doesn't. It only does that search if you write use A::B::C, no A::B::C or require A::B::C. Merely mentioning the A::B::C package (for example, to call a constructor) does not force Perl to attempt to load the module.

      The following code does not attempt to load "This/File/Does/No/Exist/On/My/Disk.pm"...

      use strict; use warnings; { package This::File::Does::No::Exist::On::My::Disk; require Math::BigInt; our @ISA = 'Math::BigInt'; } my $number = This::File::Does::No::Exist::On::My::Disk->new(7); print $number * 6, "\n";
      package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name