Re: Copy a builtin sub to a different name and then override
by beech (Parson) on Jun 01, 2018 at 22:31 UTC
|
#!/usr/bin/perl --
use strict;
use warnings;
use diagnostics;
BEGIN {
my $sleepcounter = 0;
*CORE::GLOBAL::hex = sub {
print qq{hex(@_)\n};
# goto &CORE::hex; ## FAIL
CORE::hex(@_);
};
*CORE::GLOBAL::sleep = sub(;@) {
print qq{sleep(@_)\n};
$sleepcounter += $_[0];
CORE::sleep(@_);
};
END { print "total sleep( $sleepcounter )\n"; }
}
print "\$]=$] \$^V=$^V\n";
sleep 1; print hex("0x50"),"\n";
sleep 2; print hex("0x50"),"\n";
__END__
$ perl core-global-sleep-override.pl
$]=5.016001 $^V=v5.16.1
hex(0x50)
1
hex(0x50)
1
total sleep( 0 )
$ perl core-global-sleep-override.pl
$]=5.020003 $^V=v5.20.3
sleep(1)
hex(0x50)
1
sleep(2)
hex(0x50)
1
total sleep( 3 )
| [reply] [d/l] |
|
This works for me under 5.016003 even without the correct prototype:
use strict;
use warnings;
warn "Version $]";
warn "Prototype", prototype "CORE::sleep";
my $sleepcounter;
BEGIN {
*CORE::GLOBAL::sleep = sub {
warn "start wrapper";
$sleepcounter += $_[0];
CORE::sleep(@_);
warn "stop wrapper";
};
}
sleep 3;
warn "total sleep( $sleepcounter )"
C:/Perl_64/bin\perl.exe d:/Users/lanx/pm/core_sleep.pl
Version 5.016003 at d:/Users/lanx/pm/core_sleep.pl line 4.
Prototype;$ at d:/Users/lanx/pm/core_sleep.pl line 5.
start wrapper at d:/Users/lanx/pm/core_sleep.pl line 13.
stop wrapper at d:/Users/lanx/pm/core_sleep.pl line 16.
total sleep( 3 ) at d:/Users/lanx/pm/core_sleep.pl line 26.
| [reply] [d/l] [select] |
|
#!/usr/bin/env perl
use strict;
use warnings;
my $total_sleep_time = 0;
BEGIN {
*CORE::GLOBAL::sleep = sub(;@) { $total_sleep_time+=$_[0]; CORE::sleep
+($_[0]) }
}
# use this module and the other
# ...
print "\$]=$] \$^V=$^V\n";
sleep(2);
print "total sleep is $total_sleep_time\n";
$]=5.026002 $^V=v5.26.2
total sleep is 2
thanks | [reply] [d/l] |
|
sleep sleeps integer seconds and returns the integer number of seconds actually slept.
#!/usr/bin/perl
use strict;
use warnings;
my $total_sleep_time = 0;
BEGIN {
*CORE::GLOBAL::sleep = sub(@)
{
$total_sleep_time += CORE::sleep($_[0]);
}
}
print "\$]=$] \$^V=$^V\n";
sleep(2);
sleep(1);
sleep(1.3);
print "total sleep is $total_sleep_time\n";
$ time -p ./sleep.pl
$]=5.024001 $^V=v5.24.1
total sleep is 4
real 4.00
user 0.00
sys 0.00
| [reply] [d/l] |
|
|
|
| [reply] |
|
|
|
|
Hi Beech,
> # goto &CORE::hex; ## FAIL
I can't reproduce any problems with goto &SUB here.
Neither with hex nor with sleep .
How does it "fail" for you?
update
use strict;
use warnings;
warn "Version $]";
warn "Prototype", prototype "CORE::sleep";
my $sleepcounter;
BEGIN {
*CORE::GLOBAL::sleep = sub {
warn "start wrapper ($_[0])";
$sleepcounter += int $_[0];
goto &CORE::sleep;
};
}
warn "return: ", sleep 2.3;
warn "total sleep( $sleepcounter )";
Version 5.016003 at d:/Users/lanx/pm/core_sleep.pl line 4.
Prototype;$ at d:/Users/lanx/pm/core_sleep.pl line 5.
start wrapper (2.3) at d:/Users/lanx/pm/core_sleep.pl line 15.
return: 2 at d:/Users/lanx/pm/core_sleep.pl line 23.
total sleep( 2 ) at d:/Users/lanx/pm/core_sleep.pl line 25.
| [reply] [d/l] [select] |
|
# goto &CORE::hex; ## FAIL
This works for me under 5.016003 even without the correct prototype:
Hi,
It turns out it works as designed, it merely returns different from CORE::hex(@_) , because of the prototype . I only checked for prototype on "hex" because it worked on "sleep", I forgot I preload Time::HiRes, I should have checked CORE::hex
| [reply] [d/l] |
Re: Copy a builtin sub to a different name and then override
by LanX (Saint) on Jun 01, 2018 at 22:23 UTC
|
After reading perlsub#Overriding-Built-in-Functions
> To unambiguously refer to the built-in form, precede the built-in name with the special package qualifier CORE:: . For example, saying CORE::open() always refers to the built-in open()
You should probably simply call CORE::sleep()
Have you tested if CORE::GLOBAL::sleep() even exists before overriding? *
update
*) nope it doesn't
update
see also an explanation how to fix it with exists | [reply] |
|
You should probably simply call CORE::sleep()
yep, that worked! The builtin sleep() cam be accessed via CORE::sleep(). I have posted the code under another comment. Many Thanks!
| [reply] [d/l] |
A reply falls below the community's threshold of quality. You may see it by logging in. |
Re: Copy a builtin sub to a different name and then override
by LanX (Saint) on Jun 01, 2018 at 22:07 UTC
|
Since you are aliasing your symbols with globs you get circular calls. *
Try code refs instead
my $actual_sleep = \&CORE::GLOBAL::sleep;
# and later
$actual_sleep->($_[0])
Untested!
update
That's the normal way to install a wrapper, but I'm not sure if that's recommended with builtins. ..
*) see demo here Re^5: Copy a builtin sub to a different name and then override | [reply] [d/l] |
|
#!/usr/bin/env perl
use strict;
use warnings;
my $total_sleep_time = 0;
BEGIN {
my $actual_sleep = \&CORE::GLOBAL::sleep;
*CORE::GLOBAL::sleep = sub { $total_sleep_time+=$_[0]; $actual_sleep->
+($_[0]) }
}
# use this module and the other
# ...
sleep(2);
print "total sleep is $total_sleep_time\n";
thanks | [reply] [d/l] |
|
my $actual_sleep = exists &CORE::GLOBAL::sleep # already overridden
+ ?
? \&CORE::GLOBAL::sleep
: \&CORE::sleep
Point is you are changing sleep globally, but some other modules might be trying to do the same thing already. (well ...)
If you install your override later, you'll be playing safe.
update
even more robust with defined instead of exists , see Haarg's comment in this thread for details. | [reply] [d/l] [select] |
|
> still the same problem with this:
Really?
You still have Deep recursion on anonymous subroutine ?
As I said that's the normal way to install a wrapper, but in the case of builtins it seems risky.
calling CORE::sleep() should be the recommended way.
... but I seem to remember reading that overriding sleep used to be problematic.(?)
I'll look tomorrow into it.
| [reply] [d/l] |
|
|
|
A reply falls below the community's threshold of quality. You may see it by logging in. |
Re: Copy a builtin sub to a different name and then override
by BillKSmith (Monsignor) on Jun 02, 2018 at 13:16 UTC
|
This is not exactly what you asked for, but it is an 'approved' way to meet your requirement.
Refer to the section "Overriding Built-in Functions" in perlsub
use strict;
use warnings;
use subs 'sleep';
my $total_sleep_time;
sub sleep (;$) {
$total_sleep_time += $_[0];
CORE::sleep($_[0]);
}
sleep(2);
sleep(3);
print $total_sleep_time;
| [reply] [d/l] |
|
| [reply] |
|
As I now understand your problem, we still do not have a solution. You use one (or more) existing module(s) which call sleep(). You wish to include the module sleep time(s) in your total. I devised the following test:
C:\Users\Bill\forums\monks>type Existing_module.pm
use strict;
use warnings;
package Existing_Module;
sub Do_Something {
print "Doing something.\n";
sleep(3);
}
1
C:\Users\Bill\forums\monks>type bliako.t
use strict;
use warnings;
use lib '.';
use Test::More tests => 2;
use Existing_Module;
our $total_sleep_time;
BEGIN {
*actual_sleep = *CORE::sleep;
*CORE::GLOBAL::sleep = sub (;$) {
$total_sleep_time+=$_[0];
actual_sleep($_[0])
}
}
sleep(2);
is($total_sleep_time, 2, 'Local');
Existing_Module::Do_Something(); # Sleeps for 3 sec.
is($total_sleep_time, 2+3, 'Module');
C:\Users\Bill\forums\monks>perl bliako.t
1..2
ok 1 - Local
Doing something.
not ok 2 - Module
# Failed test 'Module'
# at bliako.t line 21.
# got: '2'
# expected: '5'
# Looks like you failed 1 test of 2.
Several proposed solutions (including my previous post) can pass the first test. I have not found any that can pass the second. I have learned not to say that anything is impossible, but it does seem that this is intended to be.
| [reply] [d/l] |
|
|
|