[Wellington-pm] comparison and assignment: insignificant optimisation
Ewen McNeill
perl at ewen.mcneill.gen.nz
Mon Jun 16 03:42:37 PDT 2014
On 16/06/14 21:59, Richard Hector wrote:
> I often find it necessary to do some comparison, then do something with
> one of the operands. Here's a common example:
>
> sub max_length { [...]
>
> What irritates me is that the length of the string is evaluated twice.
That particular one can be optimised by using map(), and further
optimised by using List::Util max():
use List::Util qw(max);
sub max_length {
return max(map { length($_) } @_);
}
Although you're trading memory (array of all lengths of strings) for
time (calculating the lengths twice for any longer ones) and avoiding an
explicit temporary variable. (A list pre-sorted by length will be
pessimal for your original algorithm; a list reverse sorted by length
will be optimal, since it'll only calculate the length of the first
element twice, and then the rest will be shorter so not re-calculated.)
Some quick testing suggests this might work to avoid the storage
requirement:
use List::Util qw(max reduce);
sub max_length {
return reduce { max($a, length($b)) } 0, @_;
}
(although it also gives me warnings of $main::a and $main::b only being
used once). OTOH, you're going to be calling max() a bunch more times
on a long list, so function call overhead might hurt -- explicitly using
the ternary operator might help, but you'd have to use a temporary
variable to avoid length($b) being evaluated twice... which is the
problem we started with.
FWIW, in your example if the optimiser knows that length($foo) is
constant for a constant input then it should be able to peephole
optimise it with a temporary variable, so it's only calculated once. I
couldn't quickly find out whether Perl's peephole optimiser (peep())
does that or not.
I guess my point here is that it may be premature optimisation unless
you have a performance problem. My concern would be readability I
think, and I'd tend to use something with max() for that reason.
> I was wondering if there was a simpler way - maybe something like one of
> those action-assignment operators, like += or ||=.
AFAICT Perl doesn't have a built in "assign if greater than" operator
:-) $foo = max($foo, $bar) is about the closest you get, and even then
you need to import max.
Ewen
More information about the Wellington-pm
mailing list