Forsaken has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

yet another puzzle which has been occupying my thoughts for a while, is it (considered) bad practice for a package to store references to its objects somewhere? For example:

package Foo; use strict; use warnings; my %objects; sub new { my $class = shift; my $self = {}; bless($self, $class); $objects{$self} = *some vitally important information*; return $self; }
The consequence of this would be that the code creating the Foo object cannot simply dereference it to invoke destruction. Obviously good documentation and a special method to get rid of objects is all it takes to circumvent the issue, but my question is still: is this "not done"?

I'd very much appreciate to hear your insights.

Remember rule one...

Replies are listed 'Best First'.
Re: Storing object references internally
by bart (Canon) on Apr 23, 2005 at 09:15 UTC
    This looks quite a bit like Abigail's Inside Out Objects — briefly introduced in Re: Naming convention for Object Variables; and take a look at the nodes listed as a reference in Class::InsideOut - yet another riff on inside out objects..

    Actually you are not storing the object itself somewhere in the class, because a hash can only use strings as hash keys. So setting

    $objects{$obj} = $info_about_me;
    is actually first stringifying the object — which works very well as long as you haven't overloaded the '""' operator — but it is no longer an actual reference. It's a different thing if you store the object somewhere in the hash value.

    If you want to purge this info from the hash when the object is destroyed, you can do that in the DESTROY method. That's what the Inside Out Objects do.

    sub DESTROY { my $self = shift; delete $objects{$self}; }
      Right, wrong example perhaps ;-) In fact in the real cases where I've used it the object ref is a hash value, not a key. Does that make any difference?

      Remember rule one...
        Yes it sure does. In hash values, references remain references, so your object won't ever go away.

        One thing you can do, is use a weak reference in the common data structure. That way, it'll be wiped when the object goes away.

        Weak references can be created using weaken() in Scalar::Util. Be sure to keep the vital link to your objects a strong reference (= not weakened), because if all you have left is weak references, the object will go away and all those references will become undef.

Re: Storing object references internally
by basje (Beadle) on Apr 23, 2005 at 09:16 UTC
    This is not a problem. The $objects{$self} is not a reference to the $Foo object. If you try to store a reference as a key in a hash, the key value will be converted into a string. See Programming Perl 8.5.1 for an explanation.
Re: Storing object references internally
by Tanktalus (Canon) on Apr 23, 2005 at 14:34 UTC

    Think about what you're doing - if this makes sense, no problem. I have code like this:

    package Foo; use strict; use warnings; #... my %cache; sub fetch { my $class = shift; my $instance = shift; return $cache{$instance} if $cache{$instance}; my $self = {}; bless ($self, $class); $cache{$instance} = $self; $self->{name} = $instance; # more initialisation. $self; }
    This allows for objects that are expensive to create (e.g., reading data from database or XML data store, etc.) to be created only once, and retrieved each time thereafter. In my scenario, the data store cannot change between the time I start my program and the end, so this is safe. If your data could change, and that could be important, then you may want to avoid caching the objects so that it gets recreated each time, which means reloading the data from the data store.

Re: Storing object references internally
by zentara (Cardinal) on Apr 23, 2005 at 11:36 UTC
Re: Storing object references internally
by tlm (Prior) on Apr 23, 2005 at 13:10 UTC

    The consequence of this would be that the code creating the Foo object cannot simply dereference it to invoke destruction.

    Just a usage micro-nit: to "dereference" means to access the value pointed to by a reference, which I think is different from what you intend in the excerpt above. It's a term that one sees more often in connection with, e.g., C pointers. E.g. if x is a C-pointer, then the expression *x is said to "dereference" the pointer. And, drawing an implicit analogy between such pointers and Perl references, $$x may be described as a "dereferencing" of scalar ref $x, for example. (Naturally, such dereferencing does not invoke the destruction of the reference or its referent.)

    the lowliest monk

Re: Storing object references internally
by DrHyde (Prior) on Apr 25, 2005 at 08:45 UTC
    As it happens, in this example you're *not* storing a reference to the object. But sure, there's nothing wrong with storing information about your objects outside the objects. That's the simplest way to create a Singleton, for example.

    If you want to store a reference to your object inside itself for whatever reason, then you will need to write your own DESTROY method to unpick the circular reference.