in reply to How to redefine a modules private function?

HaukeX already explained that constant folding is happening.

This means the value is inlined at compile time, and you'd need to intercept the compilation between sub declaration and first call.

The default answer is that you need to a hard patch of the code (no monkey patch, copy it into another namespace)

I can't remember a clean possibility to register a callback to be called right after the sub declaration.

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery

Replies are listed 'Best First'.
Re^2: How to redefine a modules private function?
by LanX (Saint) on Mar 08, 2022 at 20:43 UTC
    > IMHO the most likely approach is to trigger error handling. In case you define your own sub prior to loading the module, Perl should throw a "redefined" warning and you can intercept that via $SIG{__WARN__} -handler. I would try that.

    I tried my best.

    I was capable to intercept the warning, but it doesn't seem like it's even possible to redefine a constant. (or to be more precise: the once stored constant can't be changed)°

    Other may have more success:

    use strict; use warnings; use Data::Dump qw/pp dd/; $|=1; BEGIN { $\="\n"; my $old = $SIG{__WARN__}; $SIG{__WARN__} = sub { my ( $msg ) = @_ ; if ($msg =~ /Constant subroutine DOMAIN_PORT redefined/ ) { $SIG{__WARN__} = $old; print "REDEFINED", pp caller; package ALIEN; no warnings "redefine"; sub DOMAIN_PORT() { 666 } } } } sub ALIEN::DOMAIN_PORT() { "DUMMY" } package ALIEN; sub DOMAIN_PORT() { 53 } BEGIN { print "pre compile"; } sub test { print "Inside test: ", DOMAIN_PORT; } BEGIN { test(); print DOMAIN_PORT; }

    REDEFINED("main", "d:/tmp/pm/patch_constant.pl", 42) pre compile Inside test: 53 53

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

    update

    °) not sure what is going wrong here, maybe it's a timimg issue

      OK I'm seeing clearer now.

      1. my code was wrong in that part

      package ALIEN; no warnings "redefine"; sub DOMAIN_PORT() { 666 }

      it's better written as

      no warnings "redefine"; *ALIEN::DOMAIN_PORT = sub() { 666 };

      2. But this creates a weird error

      Attempt to free unreferenced scalar: SV 0x6917d8, Perl interpreter: 0x767b98 at d:/tmp/pm/patch_constant.pl line 41.

      Which is most likely explained by %SIG

      __DIE__/__WARN__ handlers are very special in one respect: they may be called to report (probable) errors found by the parser. In such a case the parser may be in inconsistent state, so any attempt to evaluate Perl code from such a handler will probably result in a segfault. This means that warnings or errors that result from parsing Perl should be used with extreme caution, like this:

      bottom line

      nice idea, but no luck :/

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

        To wrap things up: it works and it doesn't.

        The following code runs without errors.

        Problem is that the handler is actually called before the redefinition happens. Which means the successful change of the constant (from "Dummy" to 666) is reversed again to 53 ...

        use strict; use warnings; use Data::Dump qw/pp dd/; $|=1; BEGIN { $\="\n"; my $old = $SIG{__WARN__}; my $new_constant = sub() { 666 }; *ALIEN::DOMAIN_PORT_NEW = sub() { 666 }; $SIG{__WARN__} = sub { my ( $msg ) = @_ ; if ($msg =~ /Constant subroutine DOMAIN_PORT redefined/ ) { $SIG{__WARN__} = $old; print "REDEFINED", pp caller; print ALIEN::DOMAIN_PORT(); no warnings "redefine"; *ALIEN::DOMAIN_PORT_OLD = *ALIEN::DOMAIN_PORT; *ALIEN::DOMAIN_PORT = *ALIEN::DOMAIN_PORT_NEW; print ALIEN::DOMAIN_PORT(); } }; *ALIEN::DOMAIN_PORT = sub () {"DUMMY"}; } package ALIEN; sub DOMAIN_PORT() { 53 } BEGIN { print "pre compile"; } sub test { print "Inside test: ", DOMAIN_PORT; } test();

        REDEFINED("main", "d:/tmp/pm/patch_constant.pl", 39) DUMMY 666 pre compile Inside test: 53

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery