Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Object Suicide

by pileofrogs (Priest)
on Jun 14, 2007 at 19:21 UTC ( [id://621311]=perlquestion: print w/replies, xml ) Need Help??

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

Greetings Monks!

I've got a list full of objects that, among other things, can see if they're relevant any more. I'd like my object to undefine itself when it detects that it's irrelevant.

$self = undef;

... doesn't work. It just sets that particular "$self" variable in that particular scope to undef.

I understand that this still leaves an item in my list pointing to an undefined value. That's fine with me.

Thanks!

-Pileofrogs

Replies are listed 'Best First'.
Re: Object Suicide
by Joost (Canon) on Jun 14, 2007 at 19:30 UTC
Re: Object Suicide
by philcrow (Priest) on Jun 14, 2007 at 20:07 UTC
Re: Object Suicide
by kyle (Abbot) on Jun 14, 2007 at 19:57 UTC

    Interesting question.

    I wonder if you could do something with weaken from Scalar::Util for this. You could have the object itself keep a strong reference to itself, and then all other references would have to be weak. Then the object could drop itself at will.

    The problem is that a copy of a weak reference is not weak, so you can't just weaken yourself in the constructor and pass that out. The rest of the code would have to be disciplined enough to weaken every new object and every copy of an object's reference.

    Update: I've been fooling around with this a little bit thinking that I could use overload, but it hasn't worked. The problem is that you can't really overload '=' so that the object returns a weakened reference to itself. The best I've come up with is to have a somewhat different constructor.

    package Weakling; use Scalar::Util qw( weaken ); sub new { die 'Call as Weakling->new(my $new_weakling)' if ( defined wantarray or scalar @_ < 2 ); my $self = {}; $self->{self} = $self; bless $self, 'Weakling'; $_[1] = $self; weaken $_[1]; return; } sub suicide { delete $_[0]->{self} } package main; use Scalar::Util qw( isweak ); use Test::More 'no_plan'; Weakling->new(my $weakling); isa_ok( $weakling, 'Weakling' ); ok( isweak $weakling, 'got a weak object' ); $weakling->suicide(); ok( ! defined $weakling, 'weakling killed itself' ); Weakling->new($weakling); isa_ok( $weakling, 'Weakling' ); ok( isweak $weakling, 'got a weak object' ); TODO: { local $TODO = "Can't overload '='"; my $w2 = $weakling; ok( isweak $w2, 'copy of weakling is weak' ); }

    ...but of course this won't work for you if you already have lots of construction in the traditional my $n = Obj->new() style.

Re: Object Suicide
by jbert (Priest) on Jun 15, 2007 at 07:07 UTC
    Can't you simply drop your reference to unwanted objects?
    @objects = grep { $_->is_relevant } @objects;
    that'll throw away the ref to the object and (if there are no other references), the object will be destroyed. If you have other references, then the normal answer to that (mentioned elsewhere) is to make them weak references (which means they won't keep the object alive, but become undef when the object goes away).

    I think that latter case (keeping other references around, so having to have them weak) is pretty unusual, though. Would you mind giving us a little more detail about your problem?

Re: Object Suicide
by ysth (Canon) on Jun 14, 2007 at 22:41 UTC
    Depending on how persistently you hold on to objects, each object can have a weakref to the list of objects that it can use to remove itself from the list, and become unavailable once all references other than the list's go away.

    If that's not good enough, make all references to objects other than the list's reference be to a delegate object that looks up the real object via the list with each access.

Re: Object Suicide
by ChemBoy (Priest) on Jun 15, 2007 at 20:00 UTC

    What you're trying to do here is definitely possible, though I'm not sure it's advisable. The key is that you can't use the standard my $self = shift; boilerplate in that method, because that makes a copy of the caller's reference, rather than operating on it directly (this is usually a good thing). Rather, it would need to look something like the below:

    sub method_which_may_suicide { my ($self,@arglist) = @_; if (_should_suicide(@arglist) ) { undef $_[0]; } }

    Note that this will only destroy the reference in the immediate calling code—if you call this from another method that uses the my $self = shift; trick, it will not propagate the change to whoever called that method. And again, <symbolic hand-washing>I'm not advising you to do this, but it's there if you want it</symbolic hand-washing>. :-)



    If God had meant us to fly, he would *never* have given us the railroads.
        --Michael Flanders

Re: Object Suicide
by sfink (Deacon) on Jun 16, 2007 at 20:42 UTC
    At the cost of making all of your references circular, you could store a reference to an object's list slot within the object itself:
    foreach (@GLOBAL_OBJECT_LIST) { $_->{backref} = \$_; }
    then to commit suicide you'd do:
    undef ${ $_->{backref} };
    The nasty part of that is that none of your objects will ever get destroyed automatically because of the circular references. You could make the backrefs weak to fix that, but assuming the list really is global, then it would be much simpler to commit suicide with:
    @GLOBAL_OBJECT_LIST = grep { $_ != $self } @GLOBAL_OBJECT_LIST;

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://621311]
Approved by Joost
Front-paged by GrandFather
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (1)
As of 2024-04-25 00:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found