davido has asked for the wisdom of the Perl Monks concerning the following question:
This is something that's bothered me for awhile now, but until a few days ago I didn't take the time to investigate the "internals" involved.
Consider the following code:
use warnings; use List::Util; my $reduced = List::Util::reduce { $a + $b } 1, 2, 3, 4; print "$reduced\n";
This will generate the following output:
Name "main::a" used only once: possible typo at mytest.pl line 3. Name "main::b" used only once: possible typo at mytest.pl line 3. 10
On the other hand...
use warnings; my @sorted = sort { $a <=> $b } 1, 2, 3, 4; print "@sorted\n";
...will produce...
1 2 3 4
Given that List::Util is a core module, reduce really ought to have the same privileges as sort with respect to gracefully using $a and $b. I looked at what makes sort's code different from reduce, aside from the obvious fact that one sorts and one reduces. I began by trying to find two needles in the Perl code-base haystack (searching for a and b doesn't really narrow it down). tye was helpful in pointing me to some code in op.c.
This seems to be the relevant segment:
STATIC void S_simplify_sort(pTHX_ OP *o) { dVAR; OP *kid = cLISTOPo->op_first->op_sibling; /* get past pushmark +*/ OP *k; int descending; GV *gv; const char *gvname; bool have_scopeop; PERL_ARGS_ASSERT_SIMPLIFY_SORT; if (!(o->op_flags & OPf_STACKED)) return; GvMULTI_on(gv_fetchpvs("a", GV_ADD|GV_NOTQUAL, SVt_PV)); GvMULTI_on(gv_fetchpvs("b", GV_ADD|GV_NOTQUAL, SVt_PV)); ...
GvMULTI_on must have the effect of tricking Perl into thinking that $a and $b were already used more than once, which takes care of the warning. perlguts, says this in reference to to the SV* get_sv("package::varname", GV_ADD); function:
There are additional macros whose values may be bitwise OR'ed with the GV_ADD argument to enable certain extra features. Those bits are:
GV_ADDMULTI
Marks the variable as multiply defined, thus preventing the:
Name <varname> used only once: possible typo
warning.
I thought maybe just using GV_ADD|GV_ADDMULTI could have the same effect without an explicit call to the undocumented GvMULTI_on().
Then I looked at the relevant code in List::Utils:
void reduce(block,...) SV * block PROTOTYPE: &@ CODE: { SV *ret = sv_newmortal(); int index; GV *agv,*bgv,*gv; HV *stash; SV **args = &PL_stack_base[ax]; CV* cv = sv_2cv(block, &stash, &gv, 0); if (cv == Nullcv) { croak("Not a subroutine reference"); } if(items <= 1) { XSRETURN_UNDEF; } agv = gv_fetchpv("a", GV_ADD, SVt_PV); bgv = gv_fetchpv("b", GV_ADD, SVt_PV); ...
Ah-hah! Add a call to GvMULTI_on(), or "or"-ing (|) GV_ADDMULTI into the fetch, should yield a patch for reduce that allows it to play nice with warnings.
agv = gv_fetchpv("a", GV_ADD, SVt_PV); GvMULTI_on(agv); /* No apparent effect. */ agv = gv_fetchpv("a", GV_ADD|GV_ADDMULTI, SVt_PV); /* Nope */ agv = gv_fetchpv("a", GV_ADDMULTI, SVt_PV); /* *sigh* No. */
Which brings me here to the font of Perl wisdom, hoping someone can explain why, why not, and possibly what needs to happen (in the module or perl) to solve it. This would also help to settle the same bug in List::MoreUtils::pairwise, as well as helping me out with a pet project.
Can anyone shed some light?
Update: I'm aware of many of the previous conversations on the topic. I'm looking at this from an internals perspective; what can the XS code of these modules do to eliminate the problem, not how can I make my use of these modules not trigger warnings. Actually, BrowserUk may be on to something... time for more tests. ;)
Dave
|
---|