Dear Monks and Nuns,
lately I came across an issue with dereferencing array refs. It looks like there is some hidden "lazy deref" when an array ref is used in a foreach loop, compared to the usage as a sub argument.
Consider these two subs that do nothing but die.
The main difference is the array dereference as an argument to foreach or map.
Benchmarking is amazing:use experimental 'signatures'; sub map_die ($ar) { eval {map {die} @$ar}; } sub for_die ($ar) { eval { for (@$ar) { die; } } }
use Benchmark 'cmpthese'; my @arr = ((0) x 1e6); cmpthese(0, { map => sub {map_die(\@arr)}, for => sub {for_die(\@arr)}, }); __DATA__ Rate map for map 1257/s -- -100% for 1664823/s 132352% --
Then I remembered the "lazy generators" from List::Gen and gave it a try. There is some progress, but it cannot come up to foreach.
use List::Gen 'array'; sub gen_die ($ar) { eval { &array($ar)->map(sub {die}); } } cmpthese(0, { map => sub {map_die(\@arr)}, for => sub {for_die(\@arr)}, gen => sub {gen_die(\@arr)}, }); __DATA__ Rate map gen for map 1316/s -- -93% -100% gen 18831/s 1330% -- -99% for 1662271/s 126174% 8727% --
Wouldn't it be nice to have some kind of "explicit lazy dereferencing" in Perl?
Update May 10, 2024: Added the signatures feature as suggested by Danny in Re: The Virtue of Laziness.
Greetings,
🐻
In reply to The Virtue of Laziness by jo37
For: | Use: | ||
& | & | ||
< | < | ||
> | > | ||
[ | [ | ||
] | ] |