Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Scalar::Util::refaddr

37 views
Skip to first unread message

Juerd Waalboer

unread,
Oct 8, 2007, 7:02:05 AM10/8/07
to perl5-...@perl.org
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;
}

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>

Aaron Crane

unread,
Oct 8, 2007, 7:16:22 AM10/8/07
to perl5-...@perl.org
Juerd Waalboer writes:
> Does anyone know why it wasn't done in this much simpler way?
>
> sub refaddr($) {
> ref($_[0]) ? 0+$_[0] : undef
> }

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

James Mastros

unread,
Oct 8, 2007, 7:20:59 AM10/8/07
to Aaron Crane, perl5-...@perl.org
On Mon, Oct 08, 2007 at 12:16:22PM +0100, Aaron Crane wrote:
> Juerd Waalboer writes:
> > Does anyone know why it wasn't done in this much simpler way?
> >
> > 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.

-=- James Mastros

Demerphq

unread,
Oct 8, 2007, 7:20:33 AM10/8/07
to Juerd Waalboer, perl5-...@perl.org
On 10/8/07, Juerd Waalboer <ju...@convolution.nl> wrote:
> 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;
> }
>
> 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
> }

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/"

Graham Barr

unread,
Oct 8, 2007, 7:44:54 AM10/8/07
to James Mastros, Aaron Crane, perl5-...@perl.org
On Oct 8, 2007, at 6:20 AM, James Mastros wrote:
> On Mon, Oct 08, 2007 at 12:16:22PM +0100, Aaron Crane wrote:
>> Juerd Waalboer writes:
>>> Does anyone know why it wasn't done in this much simpler way?

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.

Elizabeth Mattijsen

unread,
Oct 8, 2007, 7:52:45 AM10/8/07
to demerphq, Juerd Waalboer, perl5-...@perl.org

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

jeffre...@mac.com

unread,
Oct 8, 2007, 9:26:36 AM10/8/07
to perl5-...@perl.org

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

Josh

unread,
Oct 8, 2007, 10:53:28 AM10/8/07
to Elizabeth Mattijsen, demerphq, Juerd Waalboer, perl5-...@perl.org

sub refaddr {
if ( overload::Method( $_[0], '0+' ) ) {
rebless ...;
my $refaddr = 0+$_[0];
rebless ...;
return $refaddr;
}
else {
return 0+$_[0];
}
}

--
Josh

signature.asc

Abigail

unread,
Oct 9, 2007, 5:56:42 AM10/9/07
to perl5-...@perl.org
> sub refaddr {
> if ( overload::Method( $_[0], '0+' ) ) {
> rebless ...;
> my $refaddr = 0+$_[0];
> rebless ...;
> return $refaddr;
> }
> else {
> return 0+$_[0];
> }
> }


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

A. Pagaltzis

unread,
Oct 10, 2007, 5:59:06 AM10/10/07
to perl5-...@perl.org
* Juerd Waalboer <ju...@convolution.nl> [2007-10-08 13:11]:

> 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;
> }

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

Demerphq

unread,
Oct 10, 2007, 7:02:12 AM10/10/07
to perl5-...@perl.org

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.

A. Pagaltzis

unread,
Oct 10, 2007, 7:23:41 AM10/10/07
to perl5-...@perl.org
* demerphq <deme...@gmail.com> [2007-10-10 13:05]:

> 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 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/>

Juerd Waalboer

unread,
Oct 10, 2007, 7:49:11 AM10/10/07
to perl5-...@perl.org
A. Pagaltzis skribis 2007-10-10 11:59 (+0200):
> my $addr;

> $addr .= bless $_[0], 'Scalar::Util::Fake';

Append to undef?

A. Pagaltzis

unread,
Oct 10, 2007, 7:58:27 AM10/10/07
to perl5-...@perl.org
* Juerd Waalboer <ju...@convolution.nl> [2007-10-10 13:50]:

> A. Pagaltzis skribis 2007-10-10 11:59 (+0200):
> > my $addr;
> > $addr .= bless $_[0], 'Scalar::Util::Fake';
>
> Append to undef?

Sure. Works just fine with no warnings, as does incrementing
undef.

Josh

unread,
Oct 10, 2007, 10:02:18 AM10/10/07
to perl5-...@perl.org
On Wed, Oct 10, 2007 at 11:59:06AM +0200, A. Pagaltzis wrote:
} * Juerd Waalboer <ju...@convolution.nl> [2007-10-08 13:11]:
} > 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;
} > }
}
} 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])) {

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

signature.asc

A. Pagaltzis

unread,
Oct 10, 2007, 10:48:18 AM10/10/07
to perl5-...@perl.org
* josh <twi...@gmail.com> [2007-10-10 16:05]:

> You're treating the return result of ref() and blessed() as a
> boolean and this is not true for all perl classes.

*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.

Slaven Rezic

unread,
Oct 10, 2007, 5:04:37 PM10/10/07
to perl5-...@perl.org
Juerd Waalboer <ju...@convolution.nl> writes:

> 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

Ben Morrow

unread,
Oct 10, 2007, 8:25:15 PM10/10/07
to perl5-...@perl.org

Quoth sla...@rezic.de:

>
> Can we be confident that there's no system with Hash::Util available,
> but only pure-perl Scalar::Util?

Surely any 5.8 system with no compiler that has an upgraded Scalar::Util
falls into this category?

Ben

0 new messages