Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

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


In reply to Eliminating "used only once" warnings from List::Util::reduce by davido

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (4)
As of 2024-04-24 11:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found