summaryrefslogtreecommitdiff
path: root/pod/perlpragma.pod
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2006-05-19 20:10:47 +0000
committerNicholas Clark <nick@ccl4.org>2006-05-19 20:10:47 +0000
commita550ee30cc7e50406a26a1de128b2f7acda230f4 (patch)
treeee163c0558c550d53a2e2867c2e8e2d3b39b902d /pod/perlpragma.pod
parent2f08ed66616f3d2dff916adddde669909b743769 (diff)
downloadperl-a550ee30cc7e50406a26a1de128b2f7acda230f4.tar.gz
Add perlpragma.pod, which describes how to implement user pragmata.
p4raw-id: //depot/perl@28241
Diffstat (limited to 'pod/perlpragma.pod')
-rw-r--r--pod/perlpragma.pod138
1 files changed, 138 insertions, 0 deletions
diff --git a/pod/perlpragma.pod b/pod/perlpragma.pod
new file mode 100644
index 0000000000..9267babbed
--- /dev/null
+++ b/pod/perlpragma.pod
@@ -0,0 +1,138 @@
+=head1 NAME
+
+perlpragma - how to write a user pragma
+
+=head1 DESCRIPTION
+
+A pragma is a module which influences some aspect of the compile time or run
+time behaviour of Perl, such as C<strict> or C<warnings>. With Perl 5.10 you
+are no longer limited to the built in pragmata; you can now create user
+pragmata that modify the behaviour of user functions within a lexical scope.
+
+=head1 A basic example
+
+For example, say you need to create a class implementing overloaded
+mathematical operators, and would like to provide your own pragma that
+functions much like C<use integer;> You'd like this code
+
+ use MyMaths;
+
+ my $l = MyMaths->new(1.2);
+ my $r = MyMaths->new(3.4);
+
+ print "A: ", $l + $r, "\n";
+
+ use myint;
+ print "B: ", $l + $r, "\n";
+
+ {
+ no myint;
+ print "C: ", $l + $r, "\n";
+ }
+
+ print "D: ", $l + $r, "\n";
+
+ no myint;
+ print "E: ", $l + $r, "\n";
+
+to give the output
+
+ A: 4.6
+ B: 4
+ C: 4.6
+ D: 4
+ E: 4.6
+
+I<i.e.>, where C<use myint;> is in effect, addition operations are forced
+to integer, whereas by default they are not, with the default behaviour being
+restored via C<no myint;>
+
+The minimal implementation of the package C<MyMaths> would be something like
+this:
+
+ package MyMaths;
+ use warnings;
+ use strict;
+ use myint();
+ use overload '+' => sub {
+ my ($l, $r) = @_;
+ # Pass 1 to check up one call level from here
+ if (myint::in_effect(1)) {
+ int($$l) + int($$r);
+ } else {
+ $$l + $$r;
+ }
+ };
+
+ sub new {
+ my ($class, $value) = @_;
+ bless \$value, $class;
+ }
+
+ 1;
+
+Note how we load the user pragma C<myint> with C<()> to prevent its C<import>
+being called.
+
+The interaction with the Perl compile happens inside package C<myint>:
+
+package myint;
+
+ use strict;
+ use warnings;
+
+ sub import {
+ $^H{myint} = 1;
+ }
+
+ sub unimport {
+ $^H{myint} = 0;
+ }
+
+ sub in_effect {
+ my $level = shift // 0;
+ my $hinthash = (caller($level))[10];
+ return $hinthash->{myint};
+ }
+
+ 1;
+
+As pragmata are implemented as modules, like any other module, C<use myint;>
+becomes
+
+ BEGIN {
+ require myint;
+ myint->import();
+ }
+
+and C<no myint;> is
+
+ BEGIN {
+ require myint;
+ myint->unimport();
+ }
+
+Hence the C<import> and C<unimport> routines are called at B<compile time>
+for the user's code.
+
+User pragmata store their state by writing to C<%^H>, hence these two
+routines manipulate C<%^H>. The state information in C<%^H> stored in the
+optree, and can be retrieved at runtime with C<caller>, at index 10 of the
+list of returned results. In the example pragma, retrieval is encapsulated
+into the routine C<in_effect()>. This uses C<caller(1)> to determine the
+state of C<$^H{myint}> when each line of the user's script was called, and
+therefore provide the correct semantics in the subroutine implementing the
+overloaded addition.
+
+=head1 Implementation details
+
+The optree is shared between threads, which means there is a possibility that
+the optree will outlive the particular thread (and therefore interpreter
+instance) that created it, so true Perl scalars cannot be stored in the
+optree. Instead a compact form is used, which can only store values that are
+integers (signed and unsigned), strings or C<undef> - references and
+floating point values are stringified. If you need to store multiple values
+or complex structures, you should serialise them, for example with C<pack>.
+The deletion of a hash key from C<%^H> is recorded, and as ever can be
+distinguished from the existence of a key with value C<undef> with
+C<exists>.