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.
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.
- StevanRe:I feel your pain!
Ovid on 2006-10-06T10:48:35
DESTORY?
You know, that's a typo which might inadvertently be more descriptive than the original
:) Re:I feel your pain!
Stevan on 2006-10-06T14:40:05
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
- Stevan:P