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

Hi all, We have a module that mocks time by doing:
BEGIN { no warnings qw(redefine); *CORE::GLOBAL::time =\&MYPACKAGE::time; }
Once our framework loads the module all code that calls time() is fooled. Well almost, and that's the problem. Some of our code seems to not be fooled and I'm not sure why. I expected that somehow a time function was being imported into the current package, but that doesn't seem to be true as shown by the following debugger snippet:
DB<2> c 500 Queue::MySQLQ::dequeue(/Users/foo/lib/Queue/MySQLQ.pm:500): 500: my $time = time(); DB<3> n + + Queue::MySQLQ::dequeue(/Users/foo/lib/Queue/MySQLQ.pm:501): 501: my $expire_time = $time + $WORKER_HEAR +TBEAT_FAILURE; DB<3> x $time + + 0 1238102461 DB<4> x time() + + 0 1238102486 DB<5> x __PACKAGE__ + + 0 'Queue::MySQLQ' DB<6> S Queue::MySQLQ + + Queue::MySQLQ::BEGIN Queue::MySQLQ::dequeue Queue::MySQLQ::enqueue Queue::MySQLQ::install Queue::MySQLQ::new Queue::MySQLQ::reap_queue Queue::MySQLQ::subscribe Queue::MySQLQ::subscribe_all Queue::MySQLQ::subscribe_all_generators
Why does "x time()" have such a different value than "x $time"?

The Queue::MySQLQ code uses the POSIX module. Could that be stomping on my CORE::GLOBAL::time assignment for the scope of the file? I'm at a loss here. Any pointers for debugging this further would be appreciated!

Replies are listed 'Best First'.
Re: Where does time come from? CORE::GLOBAL:time no honored.
by ikegami (Patriarch) on Mar 26, 2009 at 22:13 UTC

    Why does "x time()" have such a different value than "x $time"?

    Because 25 seconds went by between the assignment to $time and the second call to time()?

    I have no problem overridding time().

    $ cat time.pl use strict; use warnings; BEGIN { no warnings qw(redefine); *CORE::GLOBAL::time = sub { 4 }; } my $time = time(); 1; $ perl -d time.pl Loading DB routines from perl5db.pl version 1.28 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. main::(time.pl:10): my $time = time(); DB<1> n main::(time.pl:12): 1; DB<1> x $time 0 4 DB<2> x time() 0 4 DB<3> q
      Unfortunately that's not the case. I stepped through the code and evaluated them both within a few seconds of each other. Also my mock time function returns a fixed time so I would expect them to be the same. In fact "x time()" in the debugger returns the same time every time.

        That was your cue to tell us one of them was the time returned by your function, one of them is now, and to tell us which one is which. If that's the case, please do so now. If it isn't the case, please explain what your numbers are.

        Do you get the same output from my program as I do? If so, you haven't provided enough info, since overriding time clearly works for you. Please provide more information, preferably less than 25 lines that we can run to repeat the problem.

        If you do not get the same output from my program as I do, please provide the output you do get, the output of perl -V.

Re: Where does time come from? CORE::GLOBAL:time no honored. (order)
by tye (Sage) on Mar 27, 2009 at 05:08 UTC

    The "obvious" cause would be that the Queue::MyS­QLQ::deque­ue code gets compiled before that first BEGIN block gets run. I suspect you have already considered that but my scan of the thread didn't find that point specifically addressed so I thought I'd mention it.

    - tye        

      Thanks, I did not know that.
      use strict; use warnings; print("Get time1\n"); my $time1 = time(); BEGIN { print("Override\n"); no warnings qw(redefine); *CORE::GLOBAL::time = sub { 4 }; } print("Get time2\n"); my $time2 = time(); print($time1, "\n"); print($time2, "\n");
      Override Get time1 Get time2 1238164958 4
      I think you're on to something. I didn't realize that redefining CORE::GLOBAL::time would have no effect on code already compiled that uses time(). Is there a resource I can read on how this works?

        I don't think so, but here's one:

        The items in perlfunc are actually operators. Overriding of these named operators is handled by the parser, not by the overridden operator. When the parser encounters a named operator such as time it normally places an invocation of the operator in the opcode tree.

        $ perl -MO=Concise,-exec -e'time()' 1 <0> enter 2 <;> nextstate(main 1 -e:1) v 3 <0> time[t1] v <-- time operator 4 <@> leave[1 ref] vKP/REFC -e syntax OK

        But when the operator has been overloaded, it places a subroutine invocation in the opcode tree instead.

        $ perl -MO=Concise,-exec -e'BEGIN { *CORE::GLOBAL::time = sub {} } tim +e()' 1 <0> enter 2 <;> nextstate(main 3 -e:1) v 3 <0> pushmark s 4 <#> gv[*CORE::GLOBAL::time] s <-- sub name 5 <1> entersub[t2] vKS/TARG,1 <-- sub invocation 6 <@> leave[1 ref] vKP/REFC -e syntax OK

        The same goes when overriding a named operator locally.

        $ perl -MO=Concise,-exec -e'use subs qw( time ); time()' 1 <0> enter 2 <;> nextstate(main 12 -e:1) v 3 <0> pushmark s 4 <#> gv[*time] s <-- sub name 5 <1> entersub[t2] vKS/TARG,1 <-- sub invocation 6 <@> leave[1 ref] vKP/REFC -e syntax OK

        Re^2: Where does time come from? CORE::GLOBAL:time no honored. (order) has an example.