http://qs1969.pair.com?node_id=11156170


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

In that case, I suppose nested loops over the same hash are covered by saving and restoring the localized iterator?

Nope, no need. Like you quoted, the hash's contents are fetched up front.

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

Replies are listed 'Best First'.
Re^7: Why does each() always re-evaluate its argument? ("for_list" )
by LanX (Saint) on Dec 07, 2023 at 20:20 UTC
    > fetched up front.

    I'm confused, you just explained

    > > 1) There's no copying, 2) it uses the built-in iterator.

    Did you correct yourself or am I misunderstanding you?

    FWIW: I'm installing 5.38.2 for testing via Perlbrew and it takes hours...

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

      It uses the built-in iterator to obtain the keys and values from the hash and push them unto the stack before any looping is performed.

      If you want me to be more precise, no extra copying occurs.

      • The keys are copied (i.e. fresh scalars are made for the keys) since they're not found as scalars in the hash. But that has to happen no matter the interface.
      • The pointers to the scalars placed on the stack. But that has to happen no matter the interface.
      $ perl -e' use v5.14; use experimental qw( for_list ); my %h = ( a => 4, b => 6 ); my $i = 0; for my ( $k, $v ) ( %h ) { if ( !$i++ ) { ++$h{a}; ++$h{b}; } say "$k:$v"; } ' a:5 b:7
        • The pointers to the scalars placed on the stack. But that has to happen no matter the interface.

        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. It's not a guaranteed implementation detail since, as I recall, for (1..100_000) is optimized to use a counter and repeatedly modify a scalar rather than generating 100_000 distinct scalars at once.

        So I think I'm hearing that yes it does need to allocate the perl stack to 200_000 elements, and does not perform some fancy optimized use of 'each'.

        Also I would not say that "it uses the built-in iterator" unless it picks up from the current position of the internal iterator, rather than from the start of the hash. @foo= %bar always gives you the full contents of %bar, but while (my @x= each %bar) { push @foo, @x; } could omit elements if a previous 'each' iteration left off in the middle.