From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

#!./perl
use strict;
use Config;
use Scalar::Util qw(weaken unweaken isweak);
use Test::More tests => 28;
# two references, one is weakened, the other is then undef'ed.
{
my ($y,$z);
{
my $x = "foo";
$y = \$x;
$z = \$x;
}
ok(ref($y) and ref($z));
weaken($y);
ok(ref($y) and ref($z));
undef($z);
ok(not(defined($y) and defined($z)));
undef($y);
ok(not(defined($y) and defined($z)));
}
# one reference, which is weakened
{
my $y;
{
my $x = "foo";
$y = \$x;
}
ok(ref($y));
weaken($y);
ok(not defined $y);
}
my $flag;
# a circular structure
{
$flag = 0;
{
my $y = bless {}, 'Dest';
$y->{Self} = $y;
$y->{Flag} = \$flag;
weaken($y->{Self});
ok( ref($y) );
}
ok( $flag == 1 );
undef $flag;
}
# a more complicated circular structure
{
$flag = 0;
{
my $y = bless {}, 'Dest';
my $x = bless {}, 'Dest';
$x->{Ref} = $y;
$y->{Ref} = $x;
$x->{Flag} = \$flag;
$y->{Flag} = \$flag;
weaken($x->{Ref});
}
ok( $flag == 2 );
}
# deleting a weakref before the other one
{
my ($y,$z);
{
my $x = "foo";
$y = \$x;
$z = \$x;
}
weaken($y);
undef($y);
ok(not defined $y);
ok(ref($z) );
}
# isweakref
{
$a = 5;
ok(!isweak($a));
$b = \$a;
ok(!isweak($b));
weaken($b);
ok(isweak($b));
$b = \$a;
ok(!isweak($b));
my $x = {};
weaken($x->{Y} = \$a);
ok(isweak($x->{Y}));
ok(!isweak($x->{Z}));
}
# unweaken
{
my ($y,$z);
{
my $x = "foo";
$y = \$x;
$z = \$x;
}
weaken($y);
ok(isweak($y), '$y is weak after weaken()');
is($$y, "foo", '$y points at \"foo" after weaken()');
unweaken($y);
is(ref $y, "SCALAR", '$y is still a SCALAR ref after unweaken()');
ok(!isweak($y), '$y is not weak after unweaken()');
is($$y, "foo", '$y points at \"foo" after unweaken()');
undef $z;
ok(defined $y, '$y still defined after undef $z');
}
# test weaken on a read only ref
SKIP: {
# Doesn't work for older perls, see bug [perl #24506]
skip("Test does not work with perl < 5.8.3", 5) if $] < 5.008003;
# in a MAD build, constants have refcnt 2, not 1
skip("Test does not work with MAD", 5) if exists $Config{mad};
$a = eval '\"hello"';
ok(ref($a)) or print "# didn't get a ref from eval\n";
$b = $a;
eval { weaken($b) };
# we didn't die
is($@, "");
ok(isweak($b));
is($$b, "hello");
$a="";
ok(not $b) or diag("b did not go away");
}
package Dest;
sub DESTROY {
${$_[0]{Flag}} ++;
}