Re^3: A Scalar::Util::refaddr Oddity
by adrianh (Chancellor) on Sep 26, 2005 at 11:49 UTC
|
| [reply] |
|
|
Because that idiom fails if $object overloads addition to do something else.
Doh! (Can you tell I don't mess with overloading much? Wasn't even on my radar screen.) OK, then, quick perusal of overload reveals the StrVal function, which can get us back to the original "grab the right substring and convert" approach without the reblessing.
use strict;
use warnings;
use Scalar::Util qw( refaddr );
package Foo;
use overload
'0+' => sub { 0 },
q{""} => sub { "Some Object" },
fallback => 1;
package main;
use overload;
sub refaddr_pp {
return if not ref $_[0];
overload::StrVal($_[0]) =~ /0x(\w+)/;
return hex $1;
}
my $obj = bless {}, 'Foo';
my $ref = {};
print 'stringify $obj: ', "$obj", "\n";
print 'refaddr $obj: ', refaddr($obj), "\n";
print 'refaddr_pp $obj: ', refaddr_pp($obj), "\n\n";
print 'stringify $ref: ', "$ref", "\n";
print 'refaddr $ref: ', refaddr($ref), "\n";
print 'refaddr_pp $ref: ', refaddr_pp($ref), "\n\n";
Prints
stringify $obj: Some Object
refaddr $obj: 155892768
refaddr_pp $obj: 155892768
stringify $ref: HASH(0x94abd10)
refaddr $ref: 155893008
refaddr_pp $ref: 155893008
-xdg
Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.
| [reply] [d/l] [select] |
|
|
| [reply] |
|
|
|
|
|
|
|
overload::StrVal($_[0]) =~ /0x(\w+)/;
You use the same regexp as the original, but because you are no longer blessing into a known package the regexp may match the package name instead of the address. Indeed, a bug common enough to warrant the introduction of a new fatal error in perl-5.8 would give rise to exactly that situation: zen% cat t0
package A; $x = bless {}; $y = bless [], $x; print "$y";
zen% /opt/perl-5.6.1/bin/perl -wl t0
A=HASH(0x811198c)=ARRAY(0x8111a94)
zen% /opt/perl-5.8.0/bin/perl -wl t0
Attempt to bless into a reference at t0 line 1.
Admittedly it is harder to get an overloaded object inadvertently in the wrong class like this, but "0x" is not so unusual a sequence of characters that it is fair to assume it will never appear in a legitimate package name. In any case it is easy enough to fix, with either /.*0x(\w+)/ or /0x(\w+)\)\z/.
Hugo | [reply] [d/l] [select] |
|
|
| [reply] [d/l] |
|
|
use Test::More 'no_plan';
my $original = bless {}, 'Something';
isa_ok $original, 'Something';
my $copy = $original;
bless $copy, 'SomethingElse';
isa_ok $original, 'SomethingElse';
__END__
ok 1 - The object isa Something
ok 2 - The object isa SomethingElse
1..2
| [reply] [d/l] |
|
|
| [reply] |
|
|
| [reply] |
|
|
|
|
If it's backwards compatible, and if speed is the utility function, yes. Surprisingly, unless I'm missing something, it's even faster than refaddr, at least for my environment (perl 5.8.6 on linux i386).
Update: clearly, what I'm missing is reading the docs to Benchmark and proofreading my code. Stupid errors fixed, I hope. 0 + $ref still seems to be faster than the XS refaddr, which is surprising, but maybe that's the function call overhead.
use strict;
use warnings;
use Scalar::Util qw( refaddr );
use Benchmark qw( cmpthese );
my $ref = {};
cmpthese( -5, {
'xs ' => sub { refaddr $ref },
'regex' => sub { "$ref" =~ /0x(\w+)/; hex $1; },
'0+ref' => sub { 0 + $ref },
});
Result:
Rate regex xs 0+ref
regex 165816/s -- -89% -97%
xs 1504549/s 807% -- -73%
0+ref 5550057/s 3247% 269% --
-xdg
Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.
| [reply] [d/l] [select] |