Re: What counts as a void context in Don't use grep in a void context?

2008-03-27 Thread Jay Savage
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?

2008-03-27 Thread Jenda Krynicky
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?

2008-03-27 Thread Rob Dixon

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?

2008-03-27 Thread Jay Savage
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?

2008-03-27 Thread Rob Dixon

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?

2008-03-26 Thread Telemachus
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?

2008-03-26 Thread John W. Krahn

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?

2008-03-26 Thread Jay Savage
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?

2008-03-26 Thread Telemachus
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?

2008-03-26 Thread Jay Savage
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?

2008-03-26 Thread Rob Dixon

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?

2008-03-26 Thread John W. Krahn

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/