Open book opened 2 months ago
- operating on a hash could be optimized to not build the whole list of values, but iterate on the hash directly instead
Another thing that could definitely be optimised internally is applying a similar optimisation to the FOR_ARRAY
case, when iterating two at a time over a call to builtin::indexed
on same array.
I.e. both of these should be done efficiently without a temporary list:
foreach my $elem ( @array ) { ... }
foreach my ( $idx, $elem ) ( builtin::indexed @array ) { ... }
aliasing
You only get that elsewhere in the language by not unpacking @_
(subs) or $_
(loops). There's no destructuring syntax that can give you aliases. Elsewhere the "= is copy" rule thwarts unpacking an alias by copying the value when you unpack it/them into scalar(s).
sub frobulate {
my ($copy, @copies) = @_;
# if you wanna do alias stuff you have
# to assign to $_[xx] but you can
# shallow modify $copy/@copies freely
...
}
When looping over hash(-ref)es you gotta do something about key randomisation anyway, and then you gotta zip them back into a list for for_list to unpack, so you'd have to do
for my ($k, $v) ( map { $_, $hash->{$_} } sort keys %$hash) {
...
}
at that point you're much more likely to get this patch past a code review:
for my $k (sort keys %$hash) {
my $v = $hash->{$k};
...
}
@leonerd
I.e. both of these should be done efficiently without a temporary list:
foreach my $elem ( @array ) { ... } foreach my ( $idx, $elem ) ( builtin::indexed @array ) { ... }
I thought the first one was already optimised?
@guest20
There's no destructuring syntax that can give you aliases.
Sure there is (at least experimentally – but which is all @book was referring to anyway):
use 5.022;
use feature 'refaliasing';
my @array = ( "a".."c" );
\my ( $x ) = \( @array );
$x = "foo";
say for @array;
@book
operating on a hash could be optimized to not build the whole list of values, but iterate on the hash directly instead
My gut reaction is that this might not actually be a good idea. People use for ( keys %hash )
as a best practice because the fact that the each
iterator is global makes it susceptible to action at a distance.
(E.g.: if you last
of out of a while ( my ( $k, $v ) = each %hash )
loop, without exhausting the iterator, and then the hash is passed to somewhere else that tries to iterate the hash the same way, then the other loop might inadvertently skip the keys you’d already iterated. Or, if your while
/each
loop passes the hash to something that calls keys
on it, you have an infinite loop that restarts over and over. Etc.)
We already have while ( my ( $k, $v ) = each %hash )
. Is it useful to have a different spelling of the exact same thing?
Plus, “aliasing” the key won’t actually alias the key. This is true for keys
(which returns copies) vs values
(which returns aliases). It’s even true for each
- which produces a copy of the key and an alias of the value! This is slightly more awkward to demonstrate, but you can:
use 5.012;
my %h = map +( $_ => $_ ), "a".."c";
while ( my ( $key_ref, $value_ref ) = \each %h ) {
( $$key_ref, $$value_ref ) = qw( foo bar );
}
say for %h;
[ A side note here is that you can’t usefully do while ( \my ( $key, $value ) = \each %h )
because each
returns an empty list when the iterator runs out, which \my ( ... )
winds up treating as an error: Assigned value is not a reference
. Looks like refaliasing
doesn’t vivify undefs into references, which off the cuff I’m not sure is a design flaw or correct choice or just an implementation bug or what. ]
@leonerd
I.e. both of these should be done efficiently without a temporary list:
foreach my $elem ( @array ) { ... } foreach my ( $idx, $elem ) ( builtin::indexed @array ) { ... }
I thought the first one was already optimised?
Yes, it is. Sorry, bad wording on my part. I meant, by comparison to the first (which is already optimised), the second should be optimised the same way.
@ap having very recently learnt about feature refaliasing
I can confidently say I hate it.
use 5.022; say $^V;
use feature 'refaliasing';
my $whatever = "whatever";
\(my $thing) = \$whatever;
$thing = "Oh no!";
say "$thing $whatever"
Aliasing via reference is experimental at main.pl line 5.
v5.34.0
Oh no! Oh no!
It breaks the = does copy
rule, hard. This is super cursed.
This post https://www.effectiveperlprogramming.com/2024/06/iterate-over-multiple-elements-at-the-same-time/ exposes some of the shortcomings of the
for_list
feature:The rest of the post comments on other missing capabilities of the feature:
The conclusion implies we could invest a little more work on the
for_list
feature: