Anonymous Classes With Private Data

A long while back (I’ll find the reference if I can) Stevan Little, author of Moose, commented that part of what he wanted for a p5mop was the ability to have truly private data in classes. Much in the way Perl 6 has $!data attributes that are simply private data, he wanted to just be able to use Perl’s regular variables in this same way.

I took this as a bit of a challenge and several iterations later, I had a working system. I then spent months trying to decide if I wanted to put it on CPAN. I kept weighing utility vs practicality. Though it is an interesting thought exercise, I have no idea if its a good idea.

A few things happened which made me soften my view. Most importantly, the great Damian Conway released Dios which does bring lots more of the Perl6 style classes to Perl5. This lead me to stop worrying that people would actually try to use my module for real heavy lifting; if you need that use Dios. Also Stevan gave a talk at YAPC::NA which showed an exciting and I think very promising reimagining of the p5mop project.

With these two projects out there mine can just be a curiosity. I kept finding myself showing it off and wondering. Finally, today Yanick Champoux found himself pondering blessed-subref-based objects and I reminded him of my module, which I had shown him at YAPC. I mentioned that I still was on the fence about releasing it to CPAN, he replied:

So I did.

I’m happy — and a little scared — to introduce Class:Anonymous to the CPAN. It may be the strangest thing I’ve put there yet.

The module itself is quite tiny and yet you get lots of cool features.

  • private data
  • no reliance on package name
  • no package at all if you have Package::Anon installed
  • no namespace cleaning necessary, import whatever functions you want, they aren’t part of your class
  • fully sub-classable (single) inheritance
  • declarative syntax for methods and method modifiers
  • customizable build-time initialization

No accessor generation yet but that may be possible.

Perhaps its time for an example:

use strict; 
use warnings;
use feature 'say';
use Class::Anonymous;
use Class::Anonymous::Utils ':all';

my $lifeform = class {
  my ($self, $name) = @_;
  method greeting => sub { "My name is $name" };
};

my $mortal = extend $lifeform => via {
  my ($self, $name, $age) = @_;
  around greeting => sub {
    my $orig = shift;
    $orig->() . " and I'm $age years old";
  };
};

my $bob = $mortal->new('Bob', 40);
say $bob->greeting;
say 'Bob is mortal' if $bob->isa($mortal);
say 'Bob is a lifeform' if $bob->isa($lifeform);

Here $lifeform and $mortal are classes, where $mortal->isa($lifeform). $bob is an instance of $mortal and therefor isa $lifeform as well. His greeting reflects his mortality by telling you his age, since age is much more important to mortals after all.

Another example, from my fellow Chicago.pm member Doug Bell (preaction), this is a read-only hash accessor class:

use strict;
use warnings;
use feature 'say';

use Class::Anonymous;
use Class::Anonymous::Utils 'method';

my $ro_hash = class {
  my ( $self, %hash ) = @_;
  for my $key ( keys %hash ) {
    method $key => sub { $hash{$key} };
  }
};

my %hash = (
  foo => 'bar',
  baz => 'fuzz',
);
my $obj = $ro_hash->new( %hash );

say $obj->foo;
say $obj->baz;

The internals are especially fun but for now I think I’ve rambled on long enough. Perhaps I’ll dive in to those in some other post. For now, happy perling!

Oh and if you think its terrible, blame Yanick!

1 Comment

Huzzah.

I was talking about this idea at lunch today, although I didn’t know anyone was doing anything about it. I’d really like to have even named classes in a variable. Here’s some ridiculous syntax to load a particular version of a module:


my $lwp123 = load_class_in $some_tar_file; # loads everything into $lpw123, not the symbol table

# everything in LWP is accessible through the variable, and now it can lazy load classes:
my $ua = $lwp123->from('LWP::UserAgent')->new;

From there, it’s easy to store multiple versions of the same module because all the info is in the archive name and the directory structure doesn’t matter.

A boy can dream. :)

Leave a comment

About Joel Berger

user-pic As I delve into the deeper Perl magic I like to share what I can.