The snippet in question is:
sub refaddr($) {
my $pkg = ref($_[0]) or return undef;
if (blessed($_[0])) {
bless $_[0], 'Scalar::Util::Fake';
}
else {
$pkg = undef;
}
"$_[0]" =~ /0x(\w+)/;
my $i = do { local $^W; hex $1 };
bless $_[0], $pkg if defined $pkg;
$i;
}
This does indeed seem a bit inefficient, especially with the double reblessing
going on that's probably only there to work around issues caused by the
stringification.
Does anyone know why it wasn't done in this much simpler way?
sub refaddr($) {
ref($_[0]) ? 0+$_[0] : undef
}
--
Met vriendelijke groet, Kind regards, Korajn salutojn,
Juerd Waalboer: Perl hacker <#####@juerd.nl> <http://juerd.nl/sig>
Convolution: ICT solutions and consultancy <sa...@convolution.nl>
Overloading.
$ cat o.pl
use strict;
{
package C;
use overload '+' => sub { 17 };
sub new { bless {}, $_[0] }
}
sub refaddr($) {
ref($_[0]) ? 0+$_[0] : undef
}
my $x = C->new;
my $y = C->new;
print refaddr $x;
print refaddr $y;
$ perl -wl o.pl
17
17
--
Aaron Crane
However, reblessing and numification is just as effective as
reblessing and stringification, but simpiler.
On the other hand, this is a silly discussion about microoptimization
of a fallback.
-=- James Mastros
Because of overloaded numification it cant be written that way. If I
overload nummification I can make that return 42 everytime. :-)
However given that they are doing the rebless logic i dont see why the
regex part is required.
sub refaddr($) {
my $pkg = ref($_[0]) or return undef;
if (blessed($_[0])) {
bless $_[0], 'Scalar::Util::Fake';
}
else {
$pkg = undef;
}
my $i = 0+$_[0];
bless $_[0], $pkg if defined $pkg;
$i;
}
Alternatively the entire rebless logic could be chucked and replaced
with a call to overload::StrVal() which i think has been around as
long as overload has,then the regex part could stay. I could have
sworn there was a numeric equivelent to overload::StrVal(), but i cant
find it documented, which suggests that if it does exist it hasnt
always, which is why the code doesnt use that.
I guess however the objective could have been to avoid using overload
at all. Alternatively it could be a speed issue. overload::StrVal() is
pretty slow as far as I recall.
Core code that looks this crufty is usually that way for a reason. ;-)
Yves
--
perl -Mre=debug -e "/just|another|perl|hacker/"
It was at one point, but it did not work on some 64bit platforms
because you need the result to be unsigned.
>>>
>>> sub refaddr($) {
>>> ref($_[0]) ? 0+$_[0] : undef
>>> }
>>
>> Overloading.
>
> However, reblessing and numification is just as effective as
> reblessing and stringification, but simpiler.
>
> On the other hand, this is a silly discussion about microoptimization
> of a fallback.
Right. On most systems today this code is not used because the XS
code is compiled when perl is installed.
Graham.
Now if there was an easy and efficient way to find out whether
numification is *not* overloaded on an object, you wouldn't have to
go through the whole rigamerole of reblessing, but simply return 0 +
$_[0], no?
Is there an easy and efficient way to check this?
Liz
Two reasons I'd hope my question might be seen as rising slightly
above the silly:
1.) Your code, Graham, is generally held out as an example of how to
do things, so you have readers as well as users. Which is why I asked
about it. I see a lot of code I don't understand on CPAN, and don't
bother asking about that, because given the general standard of CPAN
code doing so would be, well, silly.
2.) From time to time you do want to optimize Perl code, and it's
usually wise to optimize for the worst case, not the best or even the
average.
I am unsurprised to discover that the code is the way it is for good
reasons, and that my perplexity at it was a product of my ignorance.
If my question stimulates its further improvement, the result will
have be entirely unsilly.
jeffrey kegler
This will fail if the object has overloaded stringification, but no
numification overload:
#!/usr/bin/perl
use strict;
use warnings;
no warnings 'syntax';
use overload '""' => \&stringify,
;
sub refaddr ($) {
if ( overload::Method( $_[0], '0+' ) ) {
my $pkg = ref $_ [0];
bless $_ [0], 'Scalar::Util::Fake';
my $refaddr = 0+$_[0];
bless $_ [0], $pkg;
return $refaddr;
}
else {
return 0+$_[0];
}
}
sub stringify {return 17};
my $foo = bless [] => 'main';
print refaddr $foo, "\n";
__END__
Operation "+": no method found,
left argument has no overloaded magic,
right argument in overloaded package main at /tmp/foo line 19.
But you also may have '+' overloading. Or 'fallback' may have been set.
And there may be 'nomethod' overloading.
Abigail
FWIW, having established that there’s no better way to write that
function, I really dislike the way that spreads the reblessing
logic around the function based on a flag. Is there any reason
not to write it this way?
sub refaddr($) {
my $pkg = ref($_[0]) or return undef;
my $addr;
if (blessed($_[0])) {
$addr .= bless $_[0], 'Scalar::Util::Fake';
bless $_[0], $pkg;
}
else {
$addr .= $_[0];
}
$addr =~ /0x(\w+)/;
local $^W;
hex $1;
}
It’s a minor thing, I know, but I do think it makes the code
better.
--
*AUTOLOAD=*_;sub _{s/(.*)::(.*)/print$2,(",$\/"," ")[defined wantarray]/e;$1}
&Just->another->Perl->hack;
#Aristotle
Only thing that comes to mind while we microanalyse this little used
piece of fallback code is that we should probably ALSO look at the
code for blessed().
I bet you that blessed() is doing something very similar to what
refaddr() is doing itself.
I did that, and it turned out to have a problem, but for a
different reason. (Pointlessly pollutes UNIVERSAL.)
> I bet you that blessed() is doing something very similar to
> what refaddr() is doing itself.
Not very, funnily enough.
But I didn’t realise that `blessed` returns the same thing as
`ref`, which allows even better micro-decoupling:
sub refaddr($) {
return undef unless ref($_[0]);
my $addr;
if (my $pkg = blessed($_[0])) {
$addr .= bless $_[0], 'Scalar::Util::Fake';
bless $_[0], $pkg;
}
else {
$addr .= $_[0];
}
$addr =~ /0x(\w+)/;
local $^W;
hex $1;
}
(Excuse the nitpickery; sweating the details to this extent is
routine for me.)
Regards,
--
Aristotle Pagaltzis // <http://plasmasturm.org/>
Append to undef?
Sure. Works just fine with no warnings, as does incrementing
undef.
You're treating the return result of ref() and blessed() as a boolean
and this is not true for all perl classes. This function is incorrect
in the face of the '0' and "\0" classes.
defined( blessed( ... ) ) is a boolean test that works.
sub refaddr (...) {
my $pkg = blessed( $_[0] );
my $addr;
if ( defined $pkg ) {
bless, $_[0], 'Scalar::Util::Fake'
$addr = 0+$_[0];
bless, $_[0], $pkg;
}
elsif ( ref $_[0] ) {
$addr = 0+$_[0];
}
return $addr;
}
Also, I simultaneously apologise for ever advocating for the existence
of those two classes. Blech. I shouldn't have.
Josh
*I* am not treating anything anyhow; Graham is. I shuffled the
code a bit without touching its semantics.
The Scalar::Util that ships with perls today has these issues
in its fallback code already. I have no opinion on whether that
should/could be fixed.
> Seen on Perl Monks:
> | I do wonder why in the refaddr code in non-XS Scalar::Util, the code
> | stringifies the reference then pulls a number out with a regex. As far
> | as I can tell in terms of complexity and time-efficiency, that's clearly
> | inferior to forcing the reference to numeric.
> -- Jeffrey Kegler at http://perlmonks.org/?node_id=643288
>
> The snippet in question is:
>
> sub refaddr($) {
> my $pkg = ref($_[0]) or return undef;
> if (blessed($_[0])) {
> bless $_[0], 'Scalar::Util::Fake';
> }
> else {
> $pkg = undef;
> }
> "$_[0]" =~ /0x(\w+)/;
> my $i = do { local $^W; hex $1 };
> bless $_[0], $pkg if defined $pkg;
> $i;
> }
>
Can we be confident that there's no system with Hash::Util available,
but only pure-perl Scalar::Util?
Because:
(The XS version)
$ perl5.10.0 -e 'require Scalar::Util; require Hash::Util; $x=bless {1=>2},"Foo"; Hash::Util::lock_keys($x); warn Scalar::Util::refaddr($x)'
6948496 at -e line 1.
(The pure perl version)
$ perl5.10.0 -e '$List::Util::TESTING_PERL_ONLY=1;require Scalar::Util; require Hash::Util; $x=bless {1=>2},"Foo"; Hash::Util::lock_keys($x); warn Scalar::Util::refaddr($x)'
Modification of a read-only value attempted at (eval 5) line 21.
(This would also be an issue with "use fields")
Regards,
Slaven
--
Slaven Rezic - slaven <at> rezic <dot> de
BBBike - Routenplaner für Radfahrer in Berlin
WWW-Version: http://www.bbbike.de
Offline-Version für Unix,Mac,Windows: http://bbbike.sourceforge.net
Surely any 5.8 system with no compiler that has an upgraded Scalar::Util
falls into this category?
Ben