in reply to Re^6: "advanced" Perl functions and maintainability
in thread "advanced" Perl functions and maintainability

Right, except no one ever uses study, and most Perl hackers still pull out m// even if they only need to search for or one or two constant substrings. Also, you didn't quote meta characters in the pattern strings.

  • Comment on Re^7: "advanced" Perl functions and maintainability

Replies are listed 'Best First'.
Re^8: "advanced" Perl functions and maintainability
by itub (Priest) on Dec 13, 2004 at 16:37 UTC
    Even without using study, the speed advantage of index is almost lost when the match is at the end of a long string.

    my $string = "this is a string" x 300 . "xyz"; cmpthese(500000, { 'index' => sub { my $res; $res = index($string, "xyz"); }, regex => sub { my $res; $res = $string =~ /xyz/; }, });
             Rate regex index
    regex 97087/s    --   -2%
    index 98619/s    2%    --
    

    most Perl hackers still pull out m//...

    Ok, I agree that index is faster in some cases. However, I think there are good reasons for the behavior of most Perl hackers:

    1. m// "scales" better in terms of uses. You can use it for the simplest things as well as for very complex things. It is practical and idiomatic. To me, that sounds like a description of Perl itself.
    2. If you use it for your constant string to begin with and then you decide you need metacharacters, the change is smaller. Ok, this is a minor advantage, as the change wouldn't be that big anyway.
    3. If you are using regular expressions elsewhere in the code, the code looks more consistent, and that makes it more readable.
    4. Worring about the speed of index vs m// may be premature optimization. If you wanted the fastest possible solution you might not want to use Perl in the first place. Even if you want the fastest possible Perl implementation it is always better to make the code correct and readable first, and optimize the hot spots later.

    I realize that some of this reasons (particularly the last one) agree with your argument for using for and push instead of map. I just wasn't sure that your assertion regarding index was correct, as my benchmarks had shown the opposite in the past. Now I see that it depends on the situation.

    Regarding the readability of map vs for, I would say that a distinct advantage of map is that it documents the purpose of the loop right at the top (when used properly). As soon as you see the map keyword you'll know that you are building a list and you'll know where it is being stored; with for, you have to wait until you see the push to see the true purpose of the loop. Which approach is better depends on the intention of the coder, and I agree that the size of the block may be a factor to consider. The problem is that the exact line between map and for is blurry, partly a matter of style and personal preference.

Re^8: "advanced" Perl functions and maintainability
by Anonymous Monk on Dec 13, 2004 at 15:43 UTC
    Well, you were the one claiming they shouldn't use m// because that's more work for perl than using index, posting a benchmark to back up your claim. I posted a benchmark using different data which shows index losing. index *isn't* always faster, so Perl hackers aren't "wrong" or even inefficient for using m// over index.
    Also, you didn't quote meta characters in the pattern strings.
    Yes I did. If you think I'm wrong, please point out an unquated meta character in one of the pattern strings. If there were unquoted meta characters in the pattern strings, the benchmark wouldn't be fair, would it? index doesn't know metacharacters.

      Well, you were the one claiming they shouldn't use m// because that's more work for perl than using index, posting a benchmark to back up your claim.

      No, I didn't. You're putting words in my mouth. I claimed that many Perl hackers use m// exclusively, regardless of efficiency, then I posted bechmarks showing that, for constant substrings, index/rindex are usually faster.

      I posted a benchmark using different data which shows index losing. index *isn't* always faster, so Perl hackers aren't "wrong" or even inefficient for using m// over index.

      I never claimed it was "always" faster or that people were wrong to use m//. diotalevi tried to use efficiency as a reason to choose map instead of foreach, and I pointed out that most Perl hackers use m// regardless of its efficiency. Some never touch index/rindex. The fact is that efficiency is the last thing on their mind when they make their choice. map and m// generally take less typing, and, I guess, are much cooler, and that's the reason why so many Perl hackers live and die by them.

      Yes I did. If you think I'm wrong, please point out an unquated meta character in one of the pattern strings. If there were unquoted meta characters in the pattern strings, the benchmark wouldn't be fair, would it? index doesn't know metacharacters.

      If the scalar containing the substring to search for comes from some extenral source (e.g., supplied to your function as an argument), then you'd have to quote metacharacters in it anyway, which is usaully the only reason why I'd put a scalar inside of a pattern to begin with. Although I guess for this example you could just do away with the scalar altogether and put its contents directly in the pattern.

        Efficiency still is a reason to prefer map->assign over foreach(push). In the case of m// over index, its a case of allowing your needs to grow easily. When I use index I'm making a bet that I will only want to do exact string comparisons. That's frequently not the case over the long run so for that case, the decision often tilts toward m//.

        Again, the code isn't written to be instructional to a novice. It is written to be usable by competent perl programmers. I don't much care if a C or VB programmer doesn't understand it right away. That is, assuming the code is in a place that I don't expect novice programmers to be. If I have the expectation that someone with lowered abilities to read perl is going to need to understand it, I will write in a way that maximizes readability. Often that must means using a few more intermediate variables but I know I've switched from a map->assign to foreach(push) just for that context. It is about what is situationally appropriate. I've no hard and fast rule and I don't expect anyone else to either. I do expect that programmers will let the current priorities guide how they work.

        I should also note that while I do try to write in a style that prefers runtime efficiency over reabability by novices, I always try to keep it at a modest level and use as many layout hacks as necessary to make the structure apparent to me or someone of equal ability.