bless makes this association. Any reference type can be blessed, but these references may only be blessed into a package. Here's the trick: packages are data types in Perl, one of the 15 odd types, and you can take a reference to them: \ %{"foo::}. This means that packages can be blessed into packages. This trick involves resurrecting some of the oldest datastructures in Perl, globs and stashes, for modern, OO purposes. A whole lot of fun ensues.
package statement, but they're better known as a stash, or symbol table hash.
my to declare your variables, variables are also stored in the package, as was the way in the olden days. Functions declared like sub foo { ... }, the common way, also get stored in the stash. Normal function calls and normal method calls (like foo() and $ob->foo, and unlike $hash{value}->()) all operate on stashes.
method function that will neatly stick closures into the stash for you. This is old code I've posted before; sorry for the dup. I'm trying to turn this into a more accessible article.sub new {
# object setup (evil, run)
my $type = shift;
my %opts = @_;
my $package = $type . sprintf '::X%09d', our $counter++;
do { no strict 'refs'; push @{$package.'::ISA'}, $type; };
my $self = bless \%{$package.'::'}, $package;
sub method ($&);
do { no warnings 'redefine'; *method = sub ($&) { my $name = shift; *{"$package\::$name"} = shift; }; };
...
}
Then inside there, you can write methods like so:
my $arg;
method foo => sub {
my $self = shift;
$arg++;
$self->avast_ye();
};
$arg is a lexical variable that the method foo closes over. Each time new gets called, a new stash is created, and a new $arg gets created, and a new coderef attached to that new $arg gets created and rammed into that new stash. New everything, each go -- that's the trick.
When you write "package" in your code, you're defining a new stash. They also autovivicate (spontaneously spring into existence by their mere mention). That looks like %{"foo::"}. Yes, that's similar to a computed hash name (and also requires no strict 'refs') but the name ends in a double colon.
my $package = $type . sprintf '::X%09d', our $counter++; -- this computes a new package name based on the existing one plus a serial number.
do { no strict 'refs'; push @{$package.'::ISA'}, $type; }; -- this forces the new package to inherit from the base one, so that it in turn inherits what it inherits.
my $self = bless \%{$package.'::'}, $package; -- this creates the object as this new stash blessed into itself.
sub method ($&); do { no warnings 'redefine'; *method = sub ($&) { my $name = shift; *{"$package\::$name"} = shift; }; }; -- prototype the method function to take as args a scalar and code and define it was stuffing that code into the stash under the given name. That's the glob syntax. Stashes contain globs. Only references may be assigned into globs, and by assigning in a code reference, a new method is created.
Stashes a derivative of hashes, but rather than containing arbitrary types, they only contain typeglobs, which may in turn contain any other type. This way, you can both a $foo and a @foo, as a stash in turn can hold one of every other type.
Instance data is then hidden away in lexical variables where subclasses can't see it. That's not always what's desired. In a blessed hash, you could write $self->{foo} to get at a data item. Since stashes only contain globs, you'd have to instead write ${ $self->{foo} }. To access an array stored in a normal blessed hash, you'd write @{ $self->{foo} }, which is the same for blessed stashes. Everything is stored by reference, including scalars, in blessed stashes. Data::Alias can make this a lot easier:
use Data::Alias;
method foo => sub {
my $self = shift;
alias my @foo = @{ $self->{foo} };
push @foo, @_;
};
alias gives you fully read-write variables that are aliases to data stored in the object.
Data stored in $self is actually stored the same way that local data is stored. Only the syntax is different.
Before you get started, a few caveats: methods built out of closures (which access instance data simply as $foo rather than $self->{foo}) take a lot more memory than normal methods. Stashes don't get garbage collected at all; data stored in them is considered "global", and this data includes references to the closures and references to lexical variables. It probably contains circular references. You may think about writing a DESTROY routine to tear everything down.
-scott
Package::Generator (Score:1)
rjbs
Minor erratum (Score:1)
Actually, you can write just
%foo::if you’re not using computed stash names. That will work just fine under strictures.