Third Perl question from me in two days. Some will say I'm not researching hard enough, although I will say I'm helping keep the section active :P Either way, I'm pondering out loud in hope for an answer to be thrown my way.
Without further ado, let me quote a statement from the constant pragma's documentation:
When a constant is used in an expression, Perl replaces it with its value at compile time, and may then optimize the expression further.
I just want to be clear: does this mean that all expressions are evaluated only once per program execution? Because it also says that they are built using inlined subs, which strike me as being inherently evaluate-per-usage. I mean, if you get a sub that returns an expression, it reevaluates it per call, right? Unless they're using enclosed variables or state variables to evaluate only once, but I don't know.
To be sure, can I guarantee this will only evaluate once?
#!/usr/bin/perl
use 5.014;
use autodie;
use strict;
use warnings;
use constant TEST => do {
say 'Testing...';
5;
};
say TEST foreach (1..4);
It seems in this particular example, I can; 'Testing...' is only printed once. But is this guaranteed of all expressions I throw at it?
Yeah, yeah, yeah. I should be using Readonly on CPAN. Unfortunately I come from the Python train of thought that you should stick to a standard way of doing something as much as you can, thus I'm sticking with the antiqued constant because it's a core pragma.
Basically, if I throw a long complex sort/grep/map pipeline into a constant, can I 100% guarantee only a single evaluation?
The peephole optimizer replaces calls to constant subs with the value returned by that sub. In the runtime optree there isn't any call to that sub. For illustration:
$ perl -MO=Concise -E\
'sub answer () { 42 } for (1 .. 10) { say "The answer is ", answer }'
h <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter ->2
2 <;> nextstate(main 49 -e:1) v:%,2048 ->3
g <2> leaveloop vK/2 ->h
7 <{> enteriter(next->d last->g redo->8) lKS/8 ->e
- <0> ex-pushmark s ->3
- <1> ex-list lK ->6
3 <0> pushmark s ->4
4 <$> const(IV 1) s ->5
5 <$> const(IV 10) s ->6
6 <$> gv(*_) s ->7
- <1> null vK/1 ->g
f <|> and(other->8) vK/1 ->g
e <0> iter s ->f
- <@> lineseq vK ->-
8 <;> nextstate(main 48 -e:1) v:%,2048 ->9
c <@> say vK ->d
9 <0> pushmark s ->a
a <$> const(PV "The answer is ") s ->b
b <$> const(IV 42) s ->c
d <0> unstack v ->e
The bit of interest here is
c <@> say vK ->d
9 <0> pushmark s ->a
a <$> const(PV "The answer is ") s ->b
b <$> const(IV 42) s ->c
d <0> unstack v ->e
Which shows that the arguments to the say
operation are a const string "The answer is" and a const integer 42. There's no entersub
opcode which would represent a sub call.