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

I'm curious how to cleanly override CVs that are written in XS? More specifically, for example, we have: use Time::HiRes; and want to *Time::HiRes::gettimeofday = sub() { 42 } Fine up to this point, it works, but what if I want to restore the original XS method back? Saving and restoring glob contents doesn't work:
my $x = *Time::HiRes::gettimeofday; ... change ... *Time::HiRes::gettimeofday = $x;
and local *Time::HiRes::gettimeofday = sub {} is not acceptable, I'd like the change to persist after I quit the lexical scope. So, the question: how do I restore an overridden XS method?

Replies are listed 'Best First'.
Re: restore overridden XS methods
by Corion (Patriarch) on Mar 01, 2007 at 10:26 UTC

    It seems that saving and restoring the glob doesn't work, but saving and restoring the CODE entry in the glob works for me:

    perl -MTime::HiRes -le "my $x=*Time::HiRes::gettimeofday{CODE};*Time:: +HiRes::gettimeofday = sub(){42};print Time::HiRes::gettimeofday; *Tim +e::HiRes::gettimeofday = $x;print Time::HiRes::gettimeofday"

    or, reformatted and untested:

    use strict; use Time::HiRes; my $x=*Time::HiRes::gettimeofday{CODE}; *Time::HiRes::gettimeofday = sub(){42}; print "Modified: ", Time::HiRes::gettimeofday,"\n"; *Time::HiRes::gettimeofday = $x; print "Restored: ", Time::HiRes::gettimeofday
      Under -w, I get:
      Subroutine gettimeofday redefined at z:\test.pl line 6.
      Constant subroutine gettimeofday redefined at z:\test.pl line 8.
      Modified: 42
      Restored: 1172750176936000
      
      So, it works, kinda. With warnings.

      But unfortunately, local does not work:

      #! perl -w use strict; use Time::HiRes; { local *Time::HiRes::gettimeofday{CODE} = sub(){42}; print "Modified: ", Time::HiRes::gettimeofday,"\n"; } print "Restored: ", Time::HiRes::gettimeofday
      This results in the following compile time error:
      Can't modify glob elem in local at z:\test.pl line 5, near "} ="
      Execution of z:\test.pl aborted due to compilation errors.
      

        local works if you use glob assignment syntax:

        { local *Time::HiRes::gettimeofday = sub { print 42; }; print Time::HiRes::gettimeofday(); };; Subroutine Time::HiRes::gettimeofday redefined at (eval 4) line 1, <ST +DIN> line 2. 42 1 print Time::HiRes::gettimeofday();; 1172754765 437500

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
      Aha! It was {CODE} I was missing. Thank you very much and ++ . /me gone reading perlref.
Re: restore overridden XS methods
by Moron (Curate) on Mar 01, 2007 at 12:49 UTC
    my $x = *Time::HiRes::gettimeofday; # ... # ... # ... *Time::HiRes::gettimeofday = sub { $x; };
    worked for me and ought to be more class-independent and future-compatible.

    Update: I should have said it worked for me when testing on a core module, rather than the one actually raised! :("

    -M

    Free your mind

      doesn't seem to work for me :)

      my $x = *Time::HiRes::gettimeofday; print "original: ", Time::HiRes::gettimeofday(), "\n"; # ... *Time::HiRes::gettimeofday = sub() { $x; }; # ^^ avoids "Prototype mismatch" print "restored: ", Time::HiRes::gettimeofday(), "\n";

      prints:

      original: 117275763140928 restored: *Time::HiRes::gettimeofday

      (i.e. after having been restored, the function prints the stringified representation of the glob $x)