Building simplicidade.org: notes, projects, and occasional rants

Weaken references in Perl

In case you need circular structures in Perl, you should known about Scalar::Util and it’s weaken function.

See this example:

package T;

sub DESTROY {
  my $self = shift;
  print STDERR "Bye bye: $self->{name}\n";
}

package main;
use Scalar::Util qw( weaken );

{
  my $a = bless { name => 'a' }, 'T';
  my $b = bless { name => 'b' }, 'T';

  $a->{b} = $b;
  $b->{a} = $a;
}
print "Should see a destroy 'a' and 'b', but you wont...\n";

{
  my $c = bless { name => 'c' }, 'T';
  my $d = bless { name => 'd' }, 'T';

  $c->{d} = weaken($d);
  $d->{c} = weaken($c);
}
print "Should see a destroy 'c' and 'd'!\n";
print "Now you'll see a destroy 'a' and 'b'\n";

The output is this:

Should see a destroy 'a' and 'b', but you wont...
Bye bye: d
Bye bye: c
Should see a destroy 'c' and 'd'!
Now you'll see a destroy 'a' and 'b'
Bye bye: b
Bye bye: a

The problem is that in the first block, although the $a and $b are no longer in scope, each one holds a reference to the other, and that prevents them both from being destroyed.

In the second block, each one of $c and $d takes a weak reference to each other. Weak references don’t increment the reference count internal to all Perl variables, so at the end of the block, they are correctly destroyed.

You’ve warned.