|
Posted by szr on March 22, 2008, 10:03 am
Please log in for more thread options
Peter J. Holzer wrote:
>>> PerlFAQ Server wrote:
>>>> 6.21: What's wrong with using grep in a void context?
>>>>
>>>> The problem is that grep builds a return list, regardless of the
>>>> context. This means you're making Perl go to the trouble of
>>>> building a list that you then just throw away. If the list is
>>>> large, you waste both time and space. If your intent is to
>>>> iterate over the list, then use a for loop for this purpose.
>>>>
>>>> In perls older than 5.8.1, map suffers from this problem as
>>>> well. But since 5.8.1, this has been fixed, and map is context
>>>> aware - in void context, no lists are constructed.
>>>
>>> So why not simply make grep context aware too? Seems grep would
>>> benefit from this just as much, if not more, as map.
>>
>> You're missing the point. grep makes no sense in void context because
>> it exists to output a list.
>
> The same is true for map. If it makes no sense for grep, then it also
> doesn't make sense for map. Conversely, if it does make sense for map,
> then it also makes sense for grep.
Exactly true.
>> If you want to go a list to run some block of code, use foreach().
>
> I fully agree with this. foreach is right tool for the job.
Wont argue there.
> However, the wording of the FAQ suggests to me that *conceptually* its
> completely ok to use grep or map instead of foreach, you just
> shouldn't do it for performance reasons (and as of 5.8.1, map has
> been "fixed", so use map instead of foreach at will. TIMTOWTDI!
> Yeah!).
Yep. It's all about TIMTOWTDI, that's what always made Perl great :)
> So I'd rather write that the other way around:
>
> When grep (or map) is used in a void context, its return value is
> discarded. All that remains is the loop over its input list.
> Therefore
>
> grep { X } @arr
>
> and
>
> map { X } @arr
>
> do ultimately the same thing as
>
> do { X } for @arr;
>
> but the latter is clearer.
Yep, though some might argue the map/grep version is more elegant, and
easily chainable & nestible (think working on multi-dim arrays, where
you might nest, with at least the outter most being in voice context.
> Also, grep (and before perl 5.8.1, also map) builds the return list
> even in void context, so using the for loop is likely to be faster,
> too.
>
> On a related note, I agree with szr that grep should be optimized for
> scalar context. Constructs like
>
> my $num_matches = grep /foo/ @arr;
>
> or
>
> if (grep /foo/ @arr) { ... }
Exactly. Especially if each element is a ref, you can do something to
the refs. You can do this with 'map' in an optimized way now it seems.
'map' and 'grep' would do the same thing in this regard, though I don't
know if that warrents the optimization, but it may still be a good idea
to do so if it doesn't harm performance.
> are quite common. Instead of building a list, a simple counter can be
> used. In the second case, grep could even short-circuit and return
> true after the first match (although that is likely to break existing
> code which relies on side-effects).
How about having something along the lines of a pragma to control that
behavior (like use strict/no strict.)
--
szr
|