Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Ovid (2709)

Ovid
  (email not shown publicly)
http://publius-ovidius.livejournal.com/
AOL IM: ovidperl (Add Buddy, Send Message)

Stuff with the Perl Foundation. A couple of patches in the Perl core. A few CPAN modules. That about sums it up.

Journal of Ovid (2709)

Friday October 06, 2006
04:21 AM

Runtime Trait Woes

[ #31235 ]

For a command line program, we needed objects of different classes to show up in a special "select" list we had created, where the users could choose some, all, or none of the objects lists. I wanted to reuse the code, but the current strategy of wrapping objects in hashes to preserve extra state information (e.g., whether or not they were selected) was rather clunky. Instead, I wrote a small trait and applied it to the respective classes at runtime:

package Trait::Selected;

use strict;
use warnings;

use Class::Trait 'base';
use Scalar::Util 'refaddr';

my %is_selected;

sub is_selected {
    my $self = shift;
    my $id   = refaddr $self;
    $is_selected{$id} ||= 0;
    return $is_selected{$id} unless @_;
    $is_selected{$id} = shift;
    return $self;
}

1;

And if you want a class to have a 'selected' method, you just do this:

Class::Trait->apply( $some_class => 'Trait::Selected' );

Heck, if you don't like altering your entire class, you can just do it on a 'per instance' basis:

Class::Trait->apply( $some_instance => 'Trait::Selected' );

Then, only that instance gets the method and others don't (similar to prototyped OO).

One of the many cleanups this allowed was this:

@servers = map { $_->{selected} ? $_->{obj} : () } @servers;

To this:

@servers = grep { $_->is_selected } @servers;

Needless to say, the second is far easier to read.

But you can probably see where this is heading. What happens when an object falls out of scope and another one reuses that address? To deal with this, I have to instantiate objects like this:

my $object = $some_class->new(@args)->is_selected(0);

Any trait which is applied at runtime and maintains state could have similar issues. The only way I can think of dealing with this is to try and hook into the DESTROY mechanism, if present. Ugh.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • I had similiar ugly destruction issues when I tried to add runtime roles to Moose. In my case the actual anon-class packages were getting cleaned up (which happened when the anon-class metaclass instance went out of scope and it's DESTORY was called). It was ugly I tell you, ugly.

    - Stevan
    • DESTORY?

      You know, that's a typo which might inadvertently be more descriptive than the original :)

      • Whoops, I do that one all time too. My fingers do it, and my brain reads it as DESTROY and then I go bug hunting for hours until I finally realize and then smack myself for it. *sigh* maybe I should just switch to Java, finalize is much harder to mispell :P

        - Stevan