perlsub: Improve the "Constant Functions" documentation
authorÆvar Arnfjörð Bjarmason <avar@cpan.org>
Sat, 10 May 2014 09:26:14 +0000 (09:26 +0000)
committerRicardo Signes <rjbs@cpan.org>
Mon, 12 May 2014 14:59:31 +0000 (10:59 -0400)
Ever since perl-5.003_95-19-g5431012 which incorporated this patch:

      Title:  "Improve and update documentation of constant subs"
       From:  Tom Phoenix <rootbeer@teleport.com>
     Msg-ID:  <Pine.GSO.3.96.970331122546.14185C-100000@kelly.teleport.com>
       Date:  Mon, 31 Mar 1997 13:05:54 -0800 (PST)
      Files:  pod/perlsub.pod

We've documented that "BEGIN { my $x = 1; *X = sub () { $x } }" creates
an inlined subroutine, we just weren't doing so very explicitly. Patch
the documentation so that we now have explicit examples for the behavior
mentioned in the first paragraph of the section.

This also adds an explicit mention of the behavior reported as a bug in
[RT #79908], shows the user that you can just use B::Deparse rather than
relying on a warning to see the effects of inlining, and replaces a
contrived way to avoid inlining with just adding a "return".

While writing these docs I found a bug in the warning behavior mentioned
here, which I filed as [RT #121841]

pod/perlsub.pod

index bf08262..daa25bc 100644 (file)
@@ -1653,20 +1653,82 @@ the constant folding doesn't reduce them to a single constant:
        }
     }
 
-If you redefine a subroutine that was eligible for inlining, you'll get
-a warning by default.  (You can use this warning to tell whether or not a
-particular subroutine is considered inlinable.)  The warning is
-considered severe enough not to be affected by the B<-w>
-switch (or its absence) because previously compiled
-invocations of the function will still be using the old value of the
-function.  If you need to be able to redefine the subroutine, you need to
-ensure that it isn't inlined, either by dropping the C<()> prototype
-(which changes calling semantics, so beware) or by thwarting the
-inlining mechanism in some other way, such as
-
-    sub not_inlined () {
-       23 if $];
+As alluded to earlier you can also declare inlined subs dynamically at
+BEGIN time if their body consists of a lexically-scoped scalar which
+has no other references. Only the first example here will be inlined:
+
+    BEGIN {
+        my $var = 1;
+        no strict 'refs';
+        *INLINED = sub () { $var };
+    }
+
+    BEGIN {
+        my $var = 1;
+        my $ref = \$var;
+        no strict 'refs';
+        *NOT_INLINED = sub () { $var };
+    }
+
+A not so obvious caveat with this (see [RT #79908]) is that the
+variable will be immediately inlined, and will stop behaving like a
+normal lexical variable, e.g. this will print C<79907>, not C<79908>:
+
+    BEGIN {
+        my $x = 79907;
+        *RT_79908 = sub () { $x };
+        $x++;
+    }
+    print RT_79908(); # prints 79907
+
+If you really want a subroutine with a C<()> prototype that returns a
+lexical variable you can easily force it to not be inlined by adding
+an explicit C<return>:
+
+    BEGIN {
+        my $x = 79907;
+        *RT_79908 = sub () { return $x };
+        $x++;
+    }
+    print RT_79908(); # prints 79908
+
+The easiest way to tell if a subroutine was inlined is by using
+L<B::Deparse>, consider this example of two subroutines returning
+C<1>, one with a C<()> prototype causing it to be inlined, and one
+without (with deparse output truncated for clarity):
+
+    $ perl -MO=Deparse -le 'sub ONE { 1 } if (ONE) { print ONE if ONE }'
+    sub ONE {
+        1;
+    }
+    if (ONE ) {
+        print ONE() if ONE ;
     }
+    $ perl -MO=Deparse -le 'sub ONE () { 1 } if (ONE) { print ONE if ONE }'
+    sub ONE () { 1 }
+    do {
+        print 1
+    };
+
+If you redefine a subroutine that was eligible for inlining, you'll
+get a warning by default. You can use this warning to tell whether or
+not a particular subroutine is considered inlinable, since it's
+different than the warning for overriding non-inlined subroutines:
+
+    $ perl -e 'sub one () {1} sub one () {2}'
+    Constant subroutine one redefined at -e line 1.
+    $ perl -we 'sub one {1} sub one {2}'
+    Subroutine one redefined at -e line 1.
+
+The warning is considered severe enough not to be affected by the
+B<-w> switch (or its absence) because previously compiled invocations
+of the function will still be using the old value of the function.  If
+you need to be able to redefine the subroutine, you need to ensure
+that it isn't inlined, either by dropping the C<()> prototype (which
+changes calling semantics, so beware) or by thwarting the inlining
+mechanism in some other way, e.g. by adding an explicit C<return>:
+
+    sub not_inlined () { return 23 }
 
 =head2 Overriding Built-in Functions
 X<built-in> X<override> X<CORE> X<CORE::GLOBAL>