Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Re^10: Why does each() always re-evaluate its argument? ("for_list" )

by ikegami (Patriarch)
on Dec 08, 2023 at 17:07 UTC ( [id://11156198]=note: print w/replies, xml ) Need Help??


in reply to Re^9: Why does each() always re-evaluate its argument? ("for_list" )
in thread Why does each() always re-evaluate its argument?

I believe LanX's performance concern is whether a hash with 100,000 elements must extend the perl stack to 200,000 elements before beginning the loop.

Extending the stack by one element or by 200,000 has the same fixed performance cost.

It's cheaper in fact, because it avoids 99,999 checks to see if the stack needs to be extended.

Also I would not say that "it uses the built-in iterator" unless it picks up from the current position of the internal iterator

By your logic, keys and values don't use the iterator.

my %h = ( a => 5, b => 6, c => 7 ); each %h; say for keys( %h );
b c a

That's wrong. %h in list context, keys and values all use the iterator. They just reset it first. You can see this by the fact that it's not left in its previous state.

my %h = ( a => 5, b => 6, c => 7 ); each %h; while ( my $k = each( %h ) ) { say $k; } say "--"; each %h; my @a = %h; while ( my $k = each( %h ) ) { say $k; }

If the iterator wasn't used, you'd see the same output twice. But because the iterator is used, you see something like

c a -- b c a

In fact, keys and values are specifically documented to reset the iterator, and they're specifically document to do this and nothing else in void context. (I don't know if %h in list context is specifcally documented to reset the iterator.)

Replies are listed 'Best First'.
Re^11: Why does each() always re-evaluate its argument? ("for_list" )
by NERDVANA (Deacon) on Dec 09, 2023 at 10:17 UTC

    It's fine to reset the iterator even if they don't use it, so that's not proof. But, in fact you're right; in Perl_hv_pushkv there is

    EXTEND_MORTAL(nkeys); EXTEND(SP, ext); while ((entry = hv_iternext(hv))) { if (flags & 1) { SV *keysv = newSVhek(HeKEY_hek(entry)); SvTEMP_on(keysv); PL_tmps_stack[++PL_tmps_ix] = keysv; PUSHs(keysv); } if (flags & 2) PUSHs(HeVAL(entry)); }

    I'm rather surprised they didn't optimize that to just iterate the hashtable directly. I'm sure there are some special cases handled by hv_iternext, but they could have just tested for that first.

    Extending the stack by one element or by 200,000 has the same fixed performance cost.

    How do you figure? It has to allocate the current size + 1.6MB of ram and initialize all of it. (and as the code above shows, it also has to grow the temps stack by 800KB and initialize that) Overwriting a pair of scalars in a loop would extend by 2 and probably fall within the size of the existing stack(s) anyway.

      I'm rather surprised they didn't optimize that to just iterate the hashtable directly.

      You mean inline hv_iternext? The compiler will do that if appropriate. But that's unlikely since hv_iternext is quite big. It would make no sense to put a copy of that code in the function you showed.

      How do you figure? It has to allocate the current size + 1.6MB of ram and initialize all of it.

      No initialization is needed.

        I mean like this recipe that I've seen in various places:
        STRLEN max = HvMAX(hv); STRLEN i; for (i = 0; i <= max; i++) { HE *entry = (HvARRAY(hv))[i]; for (; entry; entry = HeNEXT(entry)) {
        Of course this can only be used if it isn't magical or tied and so on, but it would be way faster than calling hv_iternext, inlined or not.
      Even if caching the whole list is faster than iterating step by step, it'll be slower if a big loop is left early.

      The question is how long that list has to be.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      see Wikisyntax for the Monastery

      ) like with last

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11156198]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (6)
As of 2024-04-18 20:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found