in reply to Re^7: Net::SSH2 test connection to remote host
in thread Net::SSH2 test connection to remote host

In my opinion, DESTROY methods should not have side effects like changing $@ (or $? or $!), and if they do, it is a bug!

That's an opinion shared by others, but other people disagree. See for instance a thread about this on p5p this summer. Note that if DESTROY wouldn't propagate changes to $@, $! or $? DESTROY would be different from other functions, because $@, $! and $? behave differently. It also means you can have code that throws an exception, but afterwards $@ isn't set (your local $@ suffers from the same problem):

sub one::DESTROY { die "foo\n"; } eval {my $x = bless [], 'one'}; say "\$\@ = $@"; __END__ $@ = (in cleanup) foo
but
sub one::DESTROY { local $@; die "foo\n"; } eval {my $x = bless [], 'one'}; say "\$\@ = $@"; __END__ $@ =
This is far from ideal as well, and I doubt it's much better than the current situation.

People have suggested a new variable, @@, where new errors get pushed onto, instead of having them override $@. But noone has written a patch to actually do this.

Replies are listed 'Best First'.
Re^9: Net::SSH2 test connection to remote host
by salva (Canon) on Oct 01, 2008 at 10:30 UTC
    ok, let me refine my comment:
    DESTROY methods should not have side effects like changing $@ unless they do it while dieing

    In other words, I have no problem if some DESTROY method dies and changes $@ while doing it.

    In practice, what I mean is that inside a DESTROY sub, if eval is used, $@ should be localized for its scope (and the same applies for $! and IO operations and $? and system, fork, etc.)

    For instance, I see no problem with this DESTROY method:

    sub DESTROY { my $self = shift; { local $@; eval { $self->whatever() }; } die "cleanup failed" unless $self->cleanup; }

    Regarding the p5p discussion, it was about whether this no-side-effects-from-DESTROY thing should be implemented at the interpreter level.