Limbic~Region has asked for the wisdom of the Perl Monks concerning the following question:

All,
I had this idea pop into my head about being able to catch and re-throw exceptions, concatenate them, get a history, etc by tying $@. I figured I would TIAS (Try It And See).
package Exception; sub TIESCALAR { bless {}, $_[0] } sub STORE { print "Setting the value of ", '$@', "\n" } sub FETCH { 42 } package main; tie $@, 'Exception' or die "Unable to do what you want\n"; my ($foo, $bar) = (0, 0); eval { $foo = 42 / $bar }; print "The value is : $@\n"; $@ = 'blah '; print "Now the value is : $@\n";
Before running the code, you might expect a few things to happen: If you picked option 4, you would be correct:

When the eval catches the illegal by 0 exception, $@ is set and yet the STORE code is not called.
When the subsequent print occurs, the value is not 42, but the actual exception and the FETCH code is not called.
When I set $@ to 'blah', it begins acting as you might expect running the STORE code.
In the last print statement it is still behaving normally (running the FETCH code).

It reverts back to the weird behavior if you do another eval/print. I can imagine the eval setting of the variable bypassing the tied interface, but how does it know to avoid it when printing in some cases but not others? Admittedly, I spent no time investigating this but does anyone want to speculate on this behavior?

Cheers - L~R

Replies are listed 'Best First'.
Re: Tying $@ - weird behavior
by !1 (Hermit) on Sep 27, 2004 at 23:38 UTC

    To further this oddity:

    package Exception; sub TIESCALAR { bless {}, $_[0] } sub STORE { print "Changing the value from '$@' to '$_[1]' (not really +)\n" } sub FETCH { print "$@\n";42 } package main; my $t = tie $@, 'Exception' or die "Unable to do what you want\n"; my ($foo, $bar) = (0, 0); $@ = "hi"; eval { $foo = 42 / $bar }; print "The value is : $@\n"; $t->STORE("taking a look"); print "Value is still: $@, though\n"; $@ = 'blah'; print "Now the value is : $@\n"; __END__ Changing the value from 'hi' to 'hi' (not really) The value is : Illegal division by zero at - line 10. Changing the value from 'Illegal division by zero at - line 10. ' to 'taking a look' (not really) Value is still: Illegal division by zero at - line 10. , though Changing the value from 'blah' to 'blah' (not really) blah Now the value is : 42

    Strange that it is actually manipulating $@ in some fashion when you assign something to it.

    Update: Ah, antirice showed me some neat tricks. The problem seems to be that the eval's capture is putting the POK flag (has valid public pointer value) on $@. So when you check $@, perl sees the POK flag and just prints what's contained in the PV. It also seems that the PV gets updated no matter what and that checking $@ in the STORE and FETCH are just getting the PV that was set. Funny thing is that the POK flag gets turned off again when you assign to $@ (guess it realizes it's magical once again?). Code and results follow:

Re: Tying $@ - weird behavior
by qumsieh (Scribe) on Sep 28, 2004 at 06:27 UTC
    I'm not at all sure about this, but I believe Perl's special variables are more like aliases or place-holders to internal variables than normal scalars. That would explain this abnormality.

    A good example (the only one I know of, really) is $|. It can assume only the values of 0 or 1, irrespective of what you try to set it to:

    print $|=5, ".\n"; __END__ 1.
    The reason for this is that the C code that handles assignment to $| does something similar to:
    if (value assigned to $| is true) return 1 else return 0;
    This allows the following magic with $|:
    print --$|, "\n" for 1 .. 10; __END__ 1 0 1 0 1 0 1 0 1 0
    Again, all of this is just speculation ;)
Re: Tying $@ - weird behavior
by Anonymous Monk on Sep 27, 2004 at 20:39 UTC
    If you add:
    $y = $@;
    After the eval line, then the output is 42 ($y has the value 42 aswell).

    If you add:
    $y = "$@";
    Then the output will be Illegal division... and $y will be set to that aswell...

      Anonymous Monk,
      It would appear that if you are making a "copy" as in the case of $y = "$@" or $y = $@ . 'asdf' it stays "illegal division by", but if you assign it to the actual value it changes. Weird ;-)

      Cheers - L~R