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

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.

  • Comment on Re^11: Why does each() always re-evaluate its argument? ("for_list" )
  • Download Code

Replies are listed 'Best First'.
Re^12: Why does each() always re-evaluate its argument? ("for_list" )
by ikegami (Patriarch) on Dec 11, 2023 at 03:02 UTC

    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.

        Of course this can only be used if it isn't magical or tied and so on

        Does it really matter if it's faster if it doesn't work?

Re^12: Why does each() always re-evaluate its argument? ("for_list" )
by LanX (Saint) on Dec 09, 2023 at 14:53 UTC
    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