tjwrona
tjwrona

Reputation: 9035

Completely destroy all traces of an object in Perl

I am writing a Perl script that gets data from a changing outside source. As data is added or removed from this outside source I would like the data structures in my Perl script to mirror the changes. I was able to do this by creating objects that store the data in a similar fashion and synchronizing the data in those objects whenever I try to access the data in my Perl script.

This works great, and gets any new data that is added to this external source; however a problem arises when any data is removed. If any data is removed I want all existing references to it in my Perl script to be destroyed as well so the user can no longer attempt to access the data without raising an error.


The only way I could think of was to undefine the internal reference to the data as soon as it is determined that the data no longer exists. It appears, however; that when a reference is undefined it doesn't remove the data stored in the location of the reference, it only deletes the data from the variable that holds the reference.


Here is a test script demonstrating my problem:

#!/usr/bin/perl

# Always use these
use strict;
use warnings;

####################################################################################################
# Package to create an object
package Object;

use Moose;

# Define attributes
has 'name' => (is => 'ro', isa => 'Str', required => 1);

####################################################################################################
# Package to test with
package test;

# Create an object
my $object1 = Object->new('name' => 'Test Object');
print 'OBJECT1 NAME: '.$object1->name()."\n";

# Create another reference to the object
my $object2 = $object1;

# Print the name
print 'OBJECT2 NAME: '.$object2->name()."\n";

# Print both references
print "\n";
print "OBJ  : $object1\n";
print "OBJ2 : $object2\n";
print "\n";

# Undefine the reference to object2
undef $object2;

# Try to print both names
print 'OBJECT1 NAME: '.$object1->name()."\n";
print 'OBJECT2 NAME: '.$object2->name()."\n";

Output: Script Output


How can I completely destroy all traces of an object so that any attempt to access it's data will result in an error?


EDIT:

Here is a different example that may explain better what I am trying to achieve.

Say I have a file object:

my $file = File->new();

Now I want to get the text in that file

my $text = $file->text();

Now I get it again (for some unknown reason)

my $text2 = $file->text();

I want to be able to modify $text and have it directly effect the contents of $text2 as well as change the actual text attribute of the file.

I'm basically trying to tie the variables together so if one changes they all change. Also if one is deleted they would all be deleted.

This would also mean if the text attribute is changed, $text1 and $text2 would also change with it to reflect the new value.

Could this be done using an alias of some sort?

Upvotes: 1

Views: 507

Answers (2)

ikegami
ikegami

Reputation: 386501

You can't free an object that's still being used. Have the object itself keep track of whether it's still valid or not.

sub new { 
   my ($class, $data) = @_;
   my $self = bless({}, $class);
   $self->{valid} = 1;
   $self->{data} = $data;
   return $self;
}

sub delete {
   my $self = shift;
   undef(%$self);
}

sub data {
   my $self = shift;
   croak("Invalid object") if !$self->{valid};
   $self->{data} = $_[0] if @_;
   return $self->{data};
}

Example:

my $o1 = Class->new('big_complex_data');
my $o2 = $o1;

say $o1->data();
say $o2->data();

$o1->delete();
say $o2->name();

Output:

big_complex_data
big_complex_data
Invalid object at a.pl line 39.

Upvotes: 2

tjd
tjd

Reputation: 4104

Perl uses reference counting to "retire" data.

What your program is doing is as follows:

  1. Create an object and assign a reference to $object1
  2. Copy that reference to $object2 and increment the object's reference count
  3. Change the value of $object2 and decrement the object's reference count.

In the end you still have a hold of the object via $object1 and it's reference count will not drop to below 1 while you keep a hold of it. Technically as your program shuts down the $object1 variable will be destroyed as it goes out of scope, at which the object's reference count will drop to 0 and perl will look for and try to call it's DESTROY method.

If you truly want to "see" an item destroyed you may want to look into defining a DESTROY method that prints out a message upon object destruction. This way you can "let go" of your last reference and still see it's destruction.

Upvotes: 2

Related Questions