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
-
SURPRISE(?): return() VS other builtin()s
by Tom Christiansen