On Jan 5, 2004, at 10:11 AM, Rob Dixon wrote:

James Edward Gray II wrote:

On Jan 5, 2004, at 9:24 AM, R. Joseph Newton wrote:


Gary Stainburn wrote:

sub new {
  my $this=shift;                # allow for CLASS->new()
  my $class=ref($this) || $this; # or $obj->new();

The docs that suggested this are in the process of being deprecated. It is not a good idea to have objects create other objects with new().

Joseph is right here, but I hope he meant to use the word 'clone' instead of 'create' in the line above.

I would disagree strongly if he had used 'clone'. The only way to clone an object is to have access to the object to be copied, so it has to be an object method. On the other hand it's just confusing to create new objects with anything other than a class method, as the data values of any existing object are irrelevant.

I was under this impression that the biggest reason to use the ref() trick above is to allow new() to act as both a constructor and a clone method (probably a bad idea).


Originally, I thought that's what Joseph was referring to. Your complaint has caused me to reread his statement though and I see that he was instead referring to using an object to call the constructor (probably another bad idea).

My mistake. Sorry for any confusion I caused.

$blocks{$name}=$self;

Don't do this. You are asking for trouble and lock-ups with a construct like this.

There are perfectly legit reasons to use this kind of construct. The Flyweight Design Pattern pops into my head immediately. The book Object Oriented Perl covers this well, if you're interested.

Class methods should be self-contained and shouldn't mess around with any data that isn't accessible through the object or class. This is the reverse of what Flyweight does, which is to add a pointer to duplicate data to the object:

$self->{flyweight} = \%Flyweight_Data;

In Object Oriented Perl (the book I mentioned), the flyweight pattern is implemented by filling a lexically scoped class data array with the objects and returning a blessed scalar containing simply the object's index in the master array.


Since we didn't see anything outside of the constructor in the posted code, I assumed (possibly incorrectly) that $blocks was some form of class data. I see no problem with setting some class data from the constructor, if needed.

I'm not sure what you're saying here Joseph, but I don't think it's
accurate. DESTROY() is the traditionally accepted place to do
something like break a circular reference and it will work just fine.
When the last reference to the object is gone, DESTROY() will be called
as part of its garbage collection process. If you break the contained
circular references at this point, you can handle them before they
become unreachable.

DESTROY is definitely not the place to break circular references. They need to be broken precisely because they contribute to the object's reference count and DESTROY will never be called implicitly until that count falls to zero.

On Jan 5, 2004, at 10:30 AM, Steve Grazzini wrote:


On Jan 5, 2004, at 10:44 AM, James Edward Gray II wrote:
DESTROY() is the traditionally accepted place to do something like
break a circular reference

Bzzzt! :-)


DESTROY can't be called *until* the circular reference is broken
(or the script exits and everything gets destroyed, regardless of
refcount).

e.g.

Normally $x is destroyed on scope exit:

  % perl -e 'sub DESTROY { warn } bless my $x = []'
  Warning: something's wrong at -e line 1.

But with a circular reference it can't be destroyed until the
script exits, which means it leaks.

  % perl -e 'sub DESTROY { warn } my $x; bless $x = \$x'
  Warning: something's wrong at -e line 1 during global destruction.

I can see I'm making friends jolly well this morning. ;)


I was thinking along the lines of breaking circular refs among the object's data, which of course works just fine:

#!/usr/bin/perl

package LinkedList;

sub new {
        my $class = shift;
        my %object;
        $object{Head} = Node->new();
        $object{Tail} = Node->new($object{Head});
        $object{Head}->point_at($object{Tail});
        return bless \%object, $class;
}

sub DESTROY {
        my $self = shift;
        print "Breaking circular ref...\n";
        $self->{Head}->point_at(undef);
        print "LinkedList destroyed.\n";
}

package Node;

sub new {
        my $class = shift;
        return bless { Contents => shift }, $class;
}

sub point_at {
        my $self = shift;
        $self->{Contents} = shift;
}

sub DESTROY { print "Node destroyed.\n"; }

package main;

print "Building LinkedList.\n";
my $object = LinkedList->new();
print "Tossing out LinkedList reference.\n";
undef $object;
print "Perl has not yet exited.\nExiting now...\n";

__END__

Gives us:

Building LinkedList.
Tossing out LinkedList reference.
Breaking circular ref...
LinkedList destroyed.
Node destroyed.
Node destroyed.
Perl has not yet exited.
Exiting now...

Looking back I can't tell if this is what the original poster meant or not. To be clear, it is too late to break the circular reference in the Node DESTROY() method of my example. You two simply may have understood what's going on better than I diid, so again I apologize.

James


-- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] <http://learn.perl.org/> <http://learn.perl.org/first-response>




Reply via email to