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

The following code shows that Class::Delegation does two things wrong. It masks the real exception and it misreports the exception as a non-existant table method. So what's a perl hacker to do? Write all my delegation code manually and toss C::D?

$w = wrapper->instance; $w->table; # Dies with the error "Could not delegate wrapper::table" package wrapper; sub instance { return bless { schema => database->new() }, shift(); } sub schema { $_[0]->{schema} } use Class::Delegation send => '-ALL', to => 'schema'; package database; sub new { bless {}, shift() } sub table { $_[0]->column } sub column { die "Some exception" }

Replies are listed 'Best First'.
Re: Class::Delegation is incompatible with exceptions?
by Jenda (Abbot) on Jun 13, 2003 at 15:24 UTC

    I would say he's to fix the module and send a patch to the author ;-) In this case it seems all you have to do is to change the exception handling code in Class::Delegation so that it only changes some exceptions and rethrows the others without change. (Note I have no idea what is C::D supposed to do.)

    Jenda
    Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
       -- Rick Osborne

    Edit by castaway: Closed small tag in signature

      I altered my local copy to rethrow exceptions but I don't understand the problem domain well enough to know whether that is a valid thing to do or whether I have to be more careful.

      For anyone that is interested, my alterations:

      # diff -u Delegation.pm~ Delegation.pm --- Delegation.pm~ Mon Apr 22 23:20:23 2002 +++ Delegation.pm Fri Jun 13 11:22:45 2003 @@ -53,6 +53,7 @@ next DELEGATOR if exists $delegated->{ +$to[0]}; foreach my $as (@as) { push @results, delegate($deleg +ated,$wantarray,$invocant,$to[0],$as,\@args); + die $@ if $@; } } elsif (@as==1) { @@ -60,6 +61,7 @@ foreach my $to (@to) { next if exists $delegated->{$t +o}; push @results, delegate($deleg +ated,$wantarray,$invocant,$to,$as[0],\@args); + die $@ if $@; } } else { @@ -69,6 +71,7 @@ my $as = shift @as; next if exists $delegated->{$t +o}; push @results, delegate($deleg +ated,$wantarray,$invocant,$to,$as,\@args); + die $@ if $@; } } }

        I think that the best thing to do would be to change the lines 96-97 from

        ? eval { [$target->$as(@$args)] } : eval { $target->$as(@$args) };
        to
        ? [$target->$as(@$args)] : $target->$as(@$args);
        I think the eval simply doesn't belong there. We know that the method does exist already thanks to the
        return unless eval { $target->can($as) };
        above and if the method feels like throwing an exception I don't think the Class::Delegate should interfere. I think we should ask TheDamian why is the eval{} there.

        Jenda
        Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
           -- Rick Osborne

        Edit by castaway: Closed small tag in signature

Re: Class::Delegation is incompatible with exceptions?
by adrianh (Chancellor) on Jun 13, 2003 at 15:29 UTC
Solved! Re: Class::Delegation *is* compatible with exceptions?
by diotalevi (Canon) on Jun 15, 2003 at 22:54 UTC

    To "fix" this problem for Class::Delegation version 1.06 (the highest currently available on CPAN.org right now) requires installing an autoload handler into the appropriate slot. In this case because the wrapper:: class delegates I'd install AUTOLOAD into that package. My current fix is to just rethrow $@ which appears to be the fix.

    This is a problem because this behaviour isn't documented - I had to read the source code to understand it. It turns out that C::D looks for a pre-existing AUTOLOAD function and if it isn't present then it installs a function which croaks with the message "Could not delegate %s". This just overrides C::D's default autohandler.

    sub wrapper::AUTOLOAD { # See http://www.perlmonks.org/index.pl?node_id=265697 # "Class::Delegation is incompatible with exceptions?" for # discussion of this function and why it is needed to get C::D # to support exceptions properly. if ($@ and not $@ =~ m{ Class\WDelegation\.pm\s+line\s+\d+.$ }xm) { die $@; } Carp::confess( "Could not delegate " . $AUTOLOAD ); }