Re: What counts as a void context in Don't use grep in a void context?
On Wed, Mar 26, 2008 at 9:47 PM, Rob Dixon [EMAIL PROTECTED] wrote: Jay Savage wrote: If you want to see grep really shine, though, think about ways you might use it to avoid calling print for every element in the return list, e.g. print join \n, grep {$_ % 2 == 0} @list; I think that's very misleading. Why should I want to avoid calling print for each element? What you've written is the sort of thing for which Perl gets a bad name - it's less readable and has no obvious benefits over print $_\n foreach grep { $_ % 2 == 0 } @list; cmpthese(1000, { 'foreach' = sub { print $_\n for grep {$_ % 2 == 0} 0..1000; }, 'join' = sub { print join \n, grep {$_ % 2 == 0} 0..1000; }, }); Rate foreachjoin foreach 40.7/s ---20% join50.8/s 25% -- 25% performance gain strikes me as a pretty obvious benefit. YMMV, of course, depending on your data and memory performance, but in general, function calls are expensive, and and print moreso than most, because it requires a system call out to the OS. Calling a function like print on each iteration through a loop is rarely the most efficient way to do business. This doesn't really have anything to do with Perl; it's true in any language. Of course, efficiency, like beauty, is in the eye of the beholder. And that's why I was clear with OP, that he should do whatever made the most sense for him in his particular situation. TIMTOWTDI isn't what gives Perl a bad name; it's what makes it the wonderful, flexible tool that it is, and crates passionate groups of users like this one. (It also doesn't print a terminating \n) I think you'll agree there are several trivial fixes for this. 'print \n' jumps immediately to mind. Best, -- jay -- This email and attachment(s): [ ] blogable; [ x ] ask first; [ ] private and confidential daggerquill [at] gmail [dot] com http://www.tuaw.com http://www.downloadsquad.com http://www.engatiki.org values of β will give rise to dom!
Re: What counts as a void context in Don't use grep in a void context?
On Wed, Mar 26, 2008 at 9:47 PM, Rob Dixon [EMAIL PROTECTED] wrote: Jay Savage wrote: If you want to see grep really shine, though, think about ways you might use it to avoid calling print for every element in the return list, e.g. print join \n, grep {$_ % 2 == 0} @list; I think that's very misleading. Why should I want to avoid calling print for each element? What you've written is the sort of thing for which Perl gets a bad name - it's less readable and has no obvious benefits over print $_\n foreach grep { $_ % 2 == 0 } @list; I do not see how is print join \n, grep {$_ % 2 == 0} @list; any less readable than print $_\n foreach grep { $_ % 2 == 0 } @list; Would perhaps a pair of braces help? print join( \n, grep {$_ % 2 == 0} @list); I want to PRINT, JOINed by a newline, all even elements from @list instead of I want to print the item and a newline for each even element from @list. A big difference. Jenda = [EMAIL PROTECTED] === http://Jenda.Krynicky.cz = When it comes to wine, women and song, wizards are allowed to get drunk and croon as much as they like. -- Terry Pratchett in Sourcery -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/
Re: What counts as a void context in Don't use grep in a void context?
Jay Savage wrote: On Wed, Mar 26, 2008 at 9:47 PM, Rob Dixon [EMAIL PROTECTED] wrote: Jay Savage wrote: If you want to see grep really shine, though, think about ways you might use it to avoid calling print for every element in the return list, e.g. print join \n, grep {$_ % 2 == 0} @list; I think that's very misleading. Why should I want to avoid calling print for each element? What you've written is the sort of thing for which Perl gets a bad name - it's less readable and has no obvious benefits over print $_\n foreach grep { $_ % 2 == 0 } @list; cmpthese(1000, { 'foreach' = sub { print $_\n for grep {$_ % 2 == 0} 0..1000; }, 'join' = sub { print join \n, grep {$_ % 2 == 0} 0..1000; }, }); Rate foreachjoin foreach 40.7/s ---20% join50.8/s 25% -- 25% performance gain strikes me as a pretty obvious benefit. YMMV, of course, depending on your data and memory performance, but in general, function calls are expensive, and and print moreso than most, because it requires a system call out to the OS. Calling a function like print on each iteration through a loop is rarely the most efficient way to do business. Yes I understood your intention, but efficiency isn't everything by any means. I believe very firmly that programs should be coded in the clearest and most obvious way possible, then tested and optimised if the performance is inadequate.The most natural way to print a list of data is simply to print each item, and to code it differently from that is to start on the road of efficiency at the cost of intelligibility. In any case, if someone offered me a way of making my program run in 20ms instead of 25ms I wouldn't be overly impressed, and certainly don't see it as a case of grep 'shining'. My guess is that optimising out print calls would be less, not more effective than with most subroutines: all it does is to append the passed-in data to the output buffer, and the system call is performed only when that buffer is filled. This doesn't really have anything to do with Perl; it's true in any language. Yes, but now you mention it I would be surprised to see this technique used in C: char buff[1] = \0; int n; char convert[10]; for (n = 0; n = 1000; n++) { sprintf(convert, %d\n, n); strcat(buff, convert); } fputs(buff, stdout); But perhaps I am wrong. Of course, efficiency, like beauty, is in the eye of the beholder. And that's why I was clear with OP, that he should do whatever made the most sense for him in his particular situation. TIMTOWTDI isn't what gives Perl a bad name; it's what makes it the wonderful, flexible tool that it is, and crates passionate groups of users like this one. My concern is that Perl has a reputation for appearing to be an unintelligible string of symbols, and I am wary of anything that even leans in that direction. (It also doesn't print a terminating \n) I think you'll agree there are several trivial fixes for this. 'print \n' jumps immediately to mind. Yes, of course. I was simply pointing out that they weren't equivalent. Cheers, Rob -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/
Re: What counts as a void context in Don't use grep in a void context?
On Thu, Mar 27, 2008 at 2:22 PM, Rob Dixon [EMAIL PROTECTED] wrote: Yes I understood your intention, but efficiency isn't everything by any means. I believe very firmly that programs should be coded in the clearest and most obvious way possible, then tested and optimised if the performance is inadequate. In general, I agree with you; but I maintain that clear and obvious are subject to interpretation. I also maintain that using grep to feed input to a for loop isn't obvious, whereas using grep to optimize out a loop is. There is nothing that grep does that can't be done in a loop, and we normally use grep when, for whatever reason, we want to avoid a loop. The most natural way to print a list of data is simply to print each item, and to code it differently from that is to start on the road of efficiency at the cost of intelligibility. Again, I don't entirely disagree. But this thread isn't about the most natural way to print lists. It's about grep. In any case, if someone offered me a way of making my program run in 20ms instead of 25ms I wouldn't be overly impressed, and certainly don't see it as a case of grep 'shining'. I think you missed my point. I may not have been clear. No, shaving a few ms off runtime isn't shining. But it's an *example* of the *type* of thing grep shines at. That is, taking loops and tunring them into blocks, and cutting out, in this case, 999 system calls. Are the savings anything to write home about? No, of course not. But the *idea* is fantastic, and in a more complicated situation often leads to not just faster execution, but saved programmer time, increased clarity, and simplified control structures. Again, it's not about a few prints in this particular made-up case. It's about the types of things grep really does well. My guess is that optimising out print calls would be less, not more effective than with most subroutines: all it does is to append the passed-in data to the output buffer, and the system call is performed only when that buffer is filled. Well, that depends entirely on what file handle you're printing to. If you're printing to STDOUT, as all these examples so far have, each newline--and therefore each pass though the loop that matches the condition--flushes the buffer. This doesn't really have anything to do with Perl; it's true in any language. Yes, but now you mention it I would be surprised to see this technique used in C: That's because C doesn't have grep. The extra variable assignments and sprintfs you need to make the equivalent C code eat up any potential gains. The situation of he two languages isn't at all comparable. TIMTOWTDI isn't what gives Perl a bad name; it's what makes it the wonderful, flexible tool that it is, and crates passionate groups of users like this one. My concern is that Perl has a reputation for appearing to be an unintelligible string of symbols, and I am wary of anything that even leans in that direction. Point well taken. But this is a thread about grep; and grep's raison d'etre is optimizing out loops. I don't think giving an example that shows grep cutting a loop is out of order. I certainly hope it wasn't unintelligible. It's also the little optimizations (like grep and map) that are built into the language that set Perl apart from the crowd. Best, -- jay -- This email and attachment(s): [ ] blogable; [ x ] ask first; [ ] private and confidential daggerquill [at] gmail [dot] com http://www.tuaw.com http://www.downloadsquad.com http://www.engatiki.org values of β will give rise to dom!
Re: What counts as a void context in Don't use grep in a void context?
Jay Savage wrote: [snip] In any case, if someone offered me a way of making my program run in 20ms instead of 25ms I wouldn't be overly impressed, and certainly don't see it as a case of grep 'shining'. I think you missed my point. I may not have been clear. No, shaving a few ms off runtime isn't shining. But it's an *example* of the *type* of thing grep shines at. That is, taking loops and tunring them into blocks, and cutting out, in this case, 999 system calls. Are the savings anything to write home about? No, of course not. But the *idea* is fantastic, and in a more complicated situation often leads to not just faster execution, but saved programmer time, increased clarity, and simplified control structures. Then as far as I can tell we concur! I thought your point was that print join \n, @list, ''; was superior to print $_\n foreach @list; whereas you meant something more like process_list(grep { $_ % 2 == 0 } @list); is superior to my @temp; foreach (@list) { push @temp, $_ if $_ % 2 == 0; } process_list(@temp); with which I would wholeheartedly agree :) I would say though that it is a shame that it was called grep. The utility is far from universally known, and the function doesn't provide a Global Regular Expression Print facility. I prefer to see it as a list mapping function: given an input list it returns an output list which is a function of the input. It can even be emulated with the map function. Again, it's not about a few prints in this particular made-up case. It's about the types of things grep really does well. My guess is that optimising out print calls would be less, not more effective than with most subroutines: all it does is to append the passed-in data to the output buffer, and the system call is performed only when that buffer is filled. Well, that depends entirely on what file handle you're printing to. If you're printing to STDOUT, as all these examples so far have, each newline--and therefore each pass though the loop that matches the condition--flushes the buffer. [snip] Now there I would disagree. Only STDERR is autoflushed: data sent to STDOUT is output only when the buffer fills, unless that is explicitly changed. Cheers, Rob -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/
What counts as a void context in Don't use grep in a void context?
This came up somewhere else, people disagreed and now I can't see it clearly anymore. Imagine you have an array filled with numbers, and you only want to print out the even ones. Fine, someone says, use grep. print $_\n for grep {$_ % 2 == 0} @testAr; But is this a void context? On the one hand you're not literally throwing away the results, but on the other hand you're also not looking to keep the list that grep builds itself. So in a sense, you seem to be creating a list just to iterate over it in the print statement. That seems to be what the Pelr FAQ has in mind here, 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. So in a context like this, would the following be better? for my $num (@testAr) { if (($num % 2) == 0 ) { print $num\n; } } So I guess my question is this: Does the FAQ (and advice like it) mean to avoid using grep *unless* you actually want to keep and use the list, or does it just mean don't use grep only for side effects? Thanks in advance. -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/
Re: What counts as a void context in Don't use grep in a void context?
Telemachus wrote: This came up somewhere else, people disagreed and now I can't see it clearly anymore. Imagine you have an array filled with numbers, and you only want to print out the even ones. Fine, someone says, use grep. print $_\n for grep {$_ % 2 == 0} @testAr; But is this a void context? No. grep() is in list context because the for (foreach) statement modifier defines a list context: perldoc perlsyn [ SNIP ] Statement Modifiers Any simple statement may optionally be followed by a SINGLE modifier, just before the terminating semicolon (or block ending). The possible modifiers are: if EXPR unless EXPR while EXPR until EXPR foreach LIST On the one hand you're not literally throwing away the results, but on the other hand you're also not looking to keep the list that grep builds itself. So in a sense, you seem to be creating a list just to iterate over it in the print statement. That seems to be what the Pelr FAQ has in mind here, This means you're making Perl go to the trouble of building a list that you then just throw away. You are not throwing it away, you are passing it through to the for statement modifier, which iterates over that list. 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. So in a context like this, would the following be better? for my $num (@testAr) { if (($num % 2) == 0 ) { print $num\n; } } That code is iterating over a larger list, assuming that @testAr contains *some* odd numbers. So I guess my question is this: Does the FAQ (and advice like it) mean to avoid using grep *unless* you actually want to keep and use the list, or does it just mean don't use grep only for side effects? Void Context: grep {$_ % 2 == 0} @testAr; Scalar Context: my $count = grep {$_ % 2 == 0} @testAr; if ( grep {$_ % 2 == 0} @testAr ) { while ( grep {$_ % 2 == 0} @testAr ) { List Context: my @evens = grep {$_ % 2 == 0} @testAr; print grep {$_ % 2 == 0} @testAr; For grep() to produce a side effect you would have to use a function/operator in the conditional that produced a side effect or modify $_ in the conditional. I don't know why you would *want* to use grep() in void context that can't be done better some other way? John -- Perl isn't a toolbox, but a small machine shop where you can special-order certain sorts of tools at low cost and in short order.-- Larry Wall -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/
Re: What counts as a void context in Don't use grep in a void context?
On Tue, Mar 25, 2008 at 11:00 PM, Telemachus [EMAIL PROTECTED] wrote: This came up somewhere else, people disagreed and now I can't see it clearly anymore. Imagine you have an array filled with numbers, and you only want to print out the even ones. Fine, someone says, use grep. print $_\n for grep {$_ % 2 == 0} @testAr; But is this a void context? On the one hand you're not literally throwing away the results, but on the other hand you're also not looking to keep the list that grep builds itself. So in a sense, you seem to be creating a list just to iterate over it in the print statement. That seems to be what the Pelr FAQ has in mind here, 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. So in a context like this, would the following be better? for my $num (@testAr) { if (($num % 2) == 0 ) { print $num\n; } } So I guess my question is this: Does the FAQ (and advice like it) mean to avoid using grep *unless* you actually want to keep and use the list, or does it just mean don't use grep only for side effects? Thanks in advance. No, you're using grep in list context. You *are* keeping the results (from grep's perspective): you're passing the result list to for. Remember, though, that grep evaluates the code in the block, once for each time through the list, so in theory, you could do things like: grep {print $_\n} 0..1000; grep {$count++ if $_ % 2 == 0} 0..1000; grep {$_++} @nums; In these examples, we really are just ignoring the return value of grep entirely; that is what the docs mean by using grep in a void context. Don't do that. grep spends memory and processor cycles building up the result list; don't waste those resources if you don't need the results. If all you want to do is iterate through a list and do something with each of the elements, there are other, more efficient, ways to do that. The examples above could be better solved by while loops, or map, depending on the context. In your case, though, you really do need the results to pass to for, so grep is the correct tool. HTH, -- jay -- This email and attachment(s): [ ] blogable; [ x ] ask first; [ ] private and confidential daggerquill [at] gmail [dot] com http://www.tuaw.com http://www.downloadsquad.com http://www.engatiki.org values of β will give rise to dom!
Re: What counts as a void context in Don't use grep in a void context?
On Mar 26, 8:24 am, [EMAIL PROTECTED] (John W. Krahn) wrote: snip Telemachus wrote: So in a context like this, would the following be better? for my $num (@testAr) { if (($num % 2) == 0 ) { print $num\n; } } That code is iterating over a larger list, assuming that @testAr contains *some* odd numbers. First, thanks for your response. This one bit confuses me: how is the if iterating over a *larger* list than the grep? Don't they both have to run through all of @testAr in order to weed out odd numbers? Is there an advantage to using grep here rather than the foreach? I don't know why you would *want* to use grep() in void context that can't be done better some other way? I don't want to - in fact, I want *not* to. My problem was that I couldn't quite see if don't use in a void context amounted to don't use grep unless you actually wish to keep the returned items in a new array. I wasn't sure whether using grep to filter results for printing was also a no no. As my question above mentions, I'm still not sure whether there is any advantage to grep or to a foreach loop with an if-test in such a case. Or have we reached a point where it's just style and choice? Thanks. -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/
Re: What counts as a void context in Don't use grep in a void context?
On Wed, Mar 26, 2008 at 9:10 AM, Telemachus [EMAIL PROTECTED] wrote: On Mar 26, 8:24 am, [EMAIL PROTECTED] (John W. Krahn) wrote: snip Telemachus wrote: So in a context like this, would the following be better? for my $num (@testAr) { if (($num % 2) == 0 ) { print $num\n; } } That code is iterating over a larger list, assuming that @testAr contains *some* odd numbers. First, thanks for your response. This one bit confuses me: how is the if iterating over a *larger* list than the grep? Don't they both have to run through all of @testAr in order to weed out odd numbers? Is there an advantage to using grep here rather than the foreach? Not a larger list than grep, a larger list than the list of even numbers. @list_list_of_all_numbers @list_of_even_numbers. You want to do something (print) with only certain items from a list that meet certain criteria. That is what grep is designed to do, so grep is appropriate. This isn't a void context, because you are using the return value. See my earlier post for some examples of grep in a void context actually looks like. There is nothing wrong with using grep to feed a while loop. It's a convenient way to turn a multi-line block of code into a single conditional expression, as you've done. If you want to see grep really shine, though, think about ways you might use it to avoid calling print for every element in the return list, e.g. print join \n, grep {$_ % 2 == 0} @list; What you are doing now isn't wrong, though, and using a plain foreach loop wouldn't be wrong, either. What works best for you will depend on how big the list is, how your system is configured, and, most importantly, what is more comfortable for you and easier on whoever will be maintaining your program. This is a clear case of the the Perl motto: There Is More Than One Way To Do It. HTH, -- jay -- This email and attachment(s): [ ] blogable; [ x ] ask first; [ ] private and confidential daggerquill [at] gmail [dot] com http://www.tuaw.com http://www.downloadsquad.com http://www.engatiki.org values of β will give rise to dom!
Re: What counts as a void context in Don't use grep in a void context?
Jay Savage wrote: If you want to see grep really shine, though, think about ways you might use it to avoid calling print for every element in the return list, e.g. print join \n, grep {$_ % 2 == 0} @list; I think that's very misleading. Why should I want to avoid calling print for each element? What you've written is the sort of thing for which Perl gets a bad name - it's less readable and has no obvious benefits over print $_\n foreach grep { $_ % 2 == 0 } @list; (It also doesn't print a terminating \n) Rob -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/
Re: What counts as a void context in Don't use grep in a void context?
Rob Dixon wrote: Jay Savage wrote: If you want to see grep really shine, though, think about ways you might use it to avoid calling print for every element in the return list, e.g. print join \n, grep {$_ % 2 == 0} @list; I think that's very misleading. Why should I want to avoid calling print for each element? Every function/subroutine has overhead, set up the stack, create lexical scope, etc. so calling print() once with a list is more efficient then calling print() N times in a foreach loop. What you've written is the sort of thing for which Perl gets a bad name - it's less readable and has no obvious benefits over print $_\n foreach grep { $_ % 2 == 0 } @list; (It also doesn't print a terminating \n) That could be fixed thusly: print map {$_ % 2 == 0 ? $_\n : ()} @list; Although this would probably be more efficient: print map $_ 1 ? () : $_\n, @list; John -- Perl isn't a toolbox, but a small machine shop where you can special-order certain sorts of tools at low cost and in short order.-- Larry Wall -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/