develooper Front page | perl.perl5.porters | Postings from August 2008

SURPRISE(?): return() VS other builtin()s

Thread Next
From:
Tom Christiansen
Date:
August 3, 2008 14:41
Subject:
SURPRISE(?): return() VS other builtin()s
Message ID:
3981.1217799661@chthon
SYNOPSIS: I've known about this for quite some time, but haven't seen
          that it's documented anywhere.  If it isn't, I think it ought
          to be.  If it is, could you please point me to where? Thanks.

The actual output of the "return-surprise" program given 
at the end of this missive when run on my system is:

    sub &A_prints prints  
    sub &A_return returns 12
    sub &a_prints prints  
    sub &a_return returns 12
    sub &B_prints prints  12
    sub &B_return returns 12
    sub &b_prints prints  12
    sub &b_return returns 12
    sub &C_prints prints  3
    sub &C_return returns 12
    sub &c_prints prints  3
    sub &c_return returns 12
    sub &D_prints prints  Drat that 
    sub &D_return returns Drat that gnat

It is only the C/c and D versions that concern me.

My questions are:

    1.  Are you surprised that the C/c's and D's behave
        quite differently despite their parallel appearance?

    2.  Are you surprised that defined &$_ raises no strict
        refs exception?  (It'd be a pain to use otherwise, though.)

    3.  Are you surprised that the calling of the functions also
        triggers no strict refs complaints?

    4.  Are you surprised that the [CcD]_print functions elicit
        no "print interpreted as function" warning?

That is, return() specifically breaks the looks-like-a-function,
acts-like-a-function rule; you know, the one that runs along the
line that if the first non-whitespace token after the keyword is a
left-paren, the corresponding right-paren terminates completely the
entire argument list.  This is demonstrably untrue in return,
and one need but compare 

        print (1+2)*4; 

with 

        return(1+2)*4;

to see this to indeed be the case.

I am *NOT* calling this a bug: it's just how perl works.

As I said, I've known about it since forever, but I do not recall
documenting it nor seeing it documented, and it is this absence of
due deescriptions that strikes me as perhaps something of a doc bug.

What do you think?

I have also provided the [abc] variants of the [ABC] functions using
well, unary variables (1, 11, 111, 1111 in unary are 1..4), so that,
should you care to uncompile this program, you can avoid the folding 
of constant expressions and thus better see how the compiler treats 
these things.  

Here's an abbreviated version of the uncompiled (unperl) output 

    sub B_return { return 12;
    sub B_prints { print 12;
    sub b_return { return +($I + $II) * $II ** $II;
    sub b_prints { print(($I + $II) * $II ** $II);
    sub C_return { return 12;
    sub C_prints { print(3) * 4;
    sub c_return { return +($I + $II) * $II ** $II;
    sub c_prints { print($I + $II) * $II ** $II;
    sub D_return { return 'Drat that ', ('a', 'b', 'c', 'd', 'e', 'f', 'g',
                    'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
                    't', 'u', 'v', 'w', 'x', 'y', 'z')['06', '13', '00', '19'];
    sub D_prints { print('Drat that '), ('a', 'b', 'c', 'd', 'e', 'f', 'g',
                    'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
                    't', 'u', 'v', 'w', 'x', 'y', 'z')['06', '13', '00', '19'];


If you *do* uncompile it, I then have further questions.  First,
some uncompiled functions:

    sub c_return {
        use warnings;
        use strict 'refs';
        BEGIN {
            $^H{'feature_say'} = q(1);
            $^H{'feature_state'} = q(1);
            $^H{'feature_switch'} = q(1);
        }
        return +($I + $II) * $II ** $II;
    }

    sub c_prints {
        use warnings;
        use strict 'refs';
        BEGIN {
            $^H{'feature_say'} = q(1);
            $^H{'feature_state'} = q(1);
            $^H{'feature_switch'} = q(1);
        }
        print($I + $II) * $II ** $II;
    }

Note that under -p, however, those two final statements in 
each function now Deparse into:

    return((($I + $II) * ($II ** $II)));

and 

    (print(($I + $II)) * ($II ** $II));

Now for my questions regarding the (un)compiled forms:

    5. Are you surprised to see the file-scoped lexical pragmata 
       explicitly propagated down into each subroutine?  

    6. Notice how compiler preserves only the refs stricture for
       the interpreter to regard.  This makes some sense, as the 
       vars and subs strictures are a compile-time thing only,
       whereas refs is runtime.  

       My concern is this: lexical pragmata are supposed to propagate
       into an eval "STRING" construct, which must first compile
       the STRING code.  If we record only strict refs, despite
       having said use strict, are the other two lost, and if not,
       why not?

Is all that um, gunk, still there forever?  Surely it gets pulled up and
out by an optimiser. I tired making sense of the B::Concise output, but my
expertise with that module's output is sub-existent.  

A simpler, smaller case:

    #!/usr/bin/env perl
    use 5.010_000;
    use warnings;
    use strict;
    our    ($I,$II);   # unary, for unperling
    INIT { ($I,$II) = (1 .. 2) }
    sub c_return { return   ($I+$II) * $II**$II    }
    sub c_prints { print    ($I+$II) * $II**$II    }
    print c_returns();
    c_prints(); 

And the "simple" output is:

    h  <@> leave[1 ref] vKP/REFC ->(end)
    1     <0> enter ->2
    2     <;> nextstate(main 45 r3:5) v:%,*,&,{,$ ->3
    6     <@> list vKPM/128 ->7
    3        <0> pushmark vM/128 ->4
    -        <1> ex-rv2sv vK/19 ->5
    4           <#> gvsv[*I] s/OURINTR ->5
    -        <1> ex-rv2sv vK/19 ->6
    5           <#> gvsv[*II] s/OURINTR ->6
    7     <;> nextstate(main 49 r3:9) v:%,*,&,{,$ ->8
    c     <@> print vK ->d
    8        <0> pushmark s ->9
    b        <1> entersub[t6] lKS/TARG,3 ->c
    -           <1> ex-list lK ->b
    9              <0> pushmark s ->a
    -              <1> ex-rv2cv sK/2 ->-
    a                 <#> gv[*c_returns] s/EARLYCV ->b
    d     <;> nextstate(main 49 r3:10) v:%,*,&,{,$ ->e
    g     <1> entersub[t8] vKS/TARG,3 ->h
    -        <1> ex-list K ->g
    e           <0> pushmark s ->f
    -           <1> ex-rv2cv sK/2 ->-
    f              <#> gv[*c_prints] s ->g

Just some things for you to ponder on a rainy Sunday afternoon.

Me, I'm off to game for the remainder of day.

--tom


#!/usr/bin/env perl

# return-surprise
# Tom Christiansen <tchrist@perl.com>
# Sun Aug  3 15:00:22 MDT 2008

use 5.010_000;

use warnings;
use strict;

while ( < {A,a,B,b,C,c,D}_{prints,return} > ) { 
    next unless defined &$_  ; # XXX
    print          "sub &$_ ";
    if    (/ret/) { print "returns ", &{\&$_} }
    elsif (/pri/) { print "prints  "; &{\&$_} }
    else          { die   "XXX  XXX";         } 
} continue {
    print "\n";
} 

exit 0;

our    ($I,$II);   # unary, for unperling
INIT { ($I,$II) = (1 .. 2) }

sub A_return {          (1+2) * 2**2           }
sub A_prints {          (1+2) * 2**2           }

sub a_return {       ($I+$II) * $II**$II       }
sub a_prints {       ($I+$II) * $II**$II       }


sub B_return { return (    (1+2) * 2**2 )      }
sub B_prints { print  (    (1+2) * 2**2 )      }

sub b_return { return ( ($I+$II) * $II**$II )  }
sub b_prints { print  ( ($I+$II) * $II**$II )  }


sub C_return { return      (1+2) * 2**2        }
sub C_prints { print       (1+2) * 2**2        }

sub c_return { return   ($I+$II) * $II**$II    }
sub c_prints { print    ($I+$II) * $II**$II    }


sub D_return { return ("Drat that "), ("a".."z")[ qw# 06 13 00 19 # ] }
sub D_prints { print  ("Drat that "), ("a".."z")[ qw# 06 13 00 19 # ] }

__END__
### Expected output follows:
sub &A_prints prints  
sub &A_return returns 12
sub &a_prints prints  
sub &a_return returns 12
sub &B_prints prints  12
sub &B_return returns 12
sub &b_prints prints  12
sub &b_return returns 12
sub &C_prints prints  3
sub &C_return returns 12
sub &c_prints prints  3
sub &c_return returns 12
sub &D_prints prints  Drat that 
sub &D_return returns Drat that gnat

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About