Reading — step 1 of 4
Learn
Each Perl package has a symbol table — a hash storing all named variables, subs, and filehandles. The package Foo's symbol table is %Foo::. Manipulating it = metaprogramming.
Inspecting:
for my $name (keys %main::) {
print "$name\n";
}
Prints every global name in main.
Globs — a typeglob *name is a single value containing slots for $name, @name, %name, &name, plus filehandle, format, etc. Assigning to a glob installs into the symbol table.
Generating accessors at runtime:
package Person;
use strict; use warnings;
sub new {
my ($class, %args) = @_;
return bless { %args }, $class;
}
for my $attr (qw(name age email)) {
no strict 'refs';
*{"Person::$attr"} = sub {
my $self = shift;
$self->{$attr} = $_[0] if @_;
return $self->{$attr};
};
}
This loop installs three methods (name, age, email) into the Person package — getters and setters in one. Class::Accessor, Moose, and most OO frameworks use this technique.
no strict 'refs' is required because we're indexing the symbol table by string. Re-enable strict immediately after with a block scope.
Aliasing names:
*foo = \&Other::bar; # foo() now calls Other::bar()
*foo = \@some_array; # @foo aliases @some_array
B::Deparse for inspecting compiled code:
perl -MO=Deparse -e 'sub greet { print "hi" }'
Shows the parsed-then-printed form. Useful for understanding what Perl turned your code into.
AUTOLOAD — fallback method dispatch:
package SafeHash;
sub new { bless {}, shift }
sub AUTOLOAD {
my ($self, @args) = @_;
our $AUTOLOAD;
my ($method) = $AUTOLOAD =~ /::(\w+)$/;
return if $method eq 'DESTROY';
if (@args) { $self->{$method} = $args[0]; }
return $self->{$method};
}
# Usage:
my $h = SafeHash->new;
$h->name("Ada"); # AUTOLOAD intercepts, sets {name}
print $h->name; # AUTOLOAD intercepts, returns {name}
Caveats:
AUTOLOADruns only if no real method exists- Always handle
DESTROY(called by GC) $AUTOLOADholds the full method name being called
Used for: ORM-style row objects, lazy import, missing-method warnings.
UNIVERSAL methods — every blessed object inherits these:
$obj->isa('SomeClass')— true if $obj is/inherits from SomeClass$obj->can('method')— returns coderef if method exists, else undef$obj->DOES('Role')— Moose/role-awareisa
if ($obj->can('serialize')) {
$obj->serialize();
}
Closures over loop variables — classic gotcha:
my @subs;
for my $i (1..3) {
push @subs, sub { return $i }; # captures $i FRESH per iteration (good)
}
print $subs[0]->(); # 1
In Perl this works correctly — my $i is scoped to each iteration. (In old for (my $i = 0; ...; ...) C-style loops, beware: $i is shared across iterations.)
Perl metaprogramming is powerful, occasionally dangerous. Frameworks like Moose hide most of it behind ergonomic APIs.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…