Easy Anonymous Objects
On use Perl; the other day revdiablo asked whether there were Anonymous objects as easily as hashrefs? any where within Moose or sitting (hiding!) on CPAN.
Well the answers posted gave a yes for both Moose & CPAN.
Here is my twist on things using something already on CPAN which uses Moose and its Class::MOP foundations: MooseX::SingletonMethod.
With this we can easily create anonymous singleton objects like so:
{ package Anonyject; use MooseX::SingletonMethod; } my @dingfirsts; for my $line ( 1..10 ) { push @dingfirsts, Anonyject->new->add_singleton_methods( ding => sub { 'ding' x $line }, dong => sub { 'dong' x $line }, line => sub { $line }, ) } for (@dingfirsts) { say "First ", $_->ding, " on line ", $_->line; }
We can show that each of these objects created have unique anonymous classes using Moose introspection:
for (@dingfirsts) { say $_->line, ': ', ( $_->meta->class_precedence_list )[0]; } # outputs # => 1: Class::MOP::Class::__ANON__::SERIAL::2 # => 2: Class::MOP::Class::__ANON__::SERIAL::3 # => 3: Class::MOP::Class::__ANON__::SERIAL::4 # => 4: Class::MOP::Class::__ANON__::SERIAL::5 # => 5: Class::MOP::Class::__ANON__::SERIAL::6 # => 6: Class::MOP::Class::__ANON__::SERIAL::7 # => 7: Class::MOP::Class::__ANON__::SERIAL::8 # => 8: Class::MOP::Class::__ANON__::SERIAL::9 # => 9: Class::MOP::Class::__ANON__::SERIAL::10 # => 10: Class::MOP::Class::__ANON__::SERIAL::11
The rest of the class chain upwards for each of these objects is:
Anonyject >> Class::MOP::Class::__ANON__::SERIAL::1 >> Moose::Object
So you can add methods or attributes to Anonyject class and they will be available to all the anonymous objects created.
NB. Class::MOP::Class::__ANON__::SERIAL::1 is where the MooseX::Singleton methods live.
So for more proof in the singleton pudding:
my $obj1 = Anonyject->new->add_singleton_methods( ding => sub { "wing" }, dong => sub { "wong" }, line => sub { 23_939 }, ); my $obj2 = Anonyject->new->add_singleton_methods( something => sub { "else" }, ); say $obj1->ding; # Says "wing" say $obj2->something; # Says "else" say $obj1->something; # Should break and now does say $obj1->broken; # Breaks properly say $obj2->dong; # And also breaks properly
And all these objects are easily extensible:
# add dingdong just to $obj2 $obj2->meta->add_method( dingdong => sub { 'dingdong!' } ); say $obj2->dingdong; # "dingdong!" # add bang to all anonymous Anonyject objects Anonyject->meta->add_method( bang => sub { 'bang ' . ( $_[0]->meta->class_precedence_list )[0] } ); say $obj1->bang; # "bang Class::MOP::Class::__ANON__::SERIAL::12" say $obj2->bang; # "bang Class::MOP::Class::__ANON__::SERIAL::13"
/I3az/
Fine, but when these anonymous objects go out of scope, Perl will reclaim the memory for instances, but not for the classes (classes remain in the _ANON_ symbol table, together with references to the “singleton methods” that were defined in those classes). So abusing this technique, especially in long-lived processes, could yield to memory leaks.
This might have been true at one point, but it’s not anymore. Anonymous classes can be GCed just fine; I created 10000 of them (one at a time) and my process’s memory usage didn’t go up. This is with 5.10.
The way it works is that each instance of the anon-class will hold on to a reference to the metaclass (for the anon-class). So the metaclass (and the package it points too) will stay around as long as there is an instance around that needs it. Once all the instances are gone, then there will no longer be any references to the metaclass and the metaclass (and associated package) can be garbage collected.
Morning guys… many thanks for all the comments thus far!
So yes anon-classes do tidy up behind themselves. From Class::MOP::Class pod:
“Anonymous classes are destroyed once the metaclass they are attached to goes out of scope, and will be removed from Perl’s internal symbol table.”
However saying that I may have a bug MooseX::SingletonMethods because quick test here seems to suggest those anon classes hang around in the symbol table. I’ll write up some proper empirical tests at weekend to get to bottom of it.
/I3az/