Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are the values printed in the foreach statement?

Tags:

foreach

perl

I am very very new to perl programming.

While reading about the loops, for the foreach loop I got two examples.

The one example is,

foreach ('hickory','dickory','doc') {
   print $_;
   print "\n";
}

Output:-

hickory
dickory
doc

The $_ variable contains the each item. So, it prints.

In another example, they said did not specified the $_ variable in print statement. The empty print statement only there. How it prints the foreach arguments.

foreach ('hickory','dickory','doc') {
   print;
   print "\n";
}

Output:-

hickory
dickory
doc

For this also the same output. How it prints the values. In that book they did not given any explanation for that. I was searched in internet. But I am not able to find anything.

like image 405
sureshkumar Avatar asked Mar 10 '23 02:03

sureshkumar


1 Answers

Your question about print in foreach being answered, here is a little more on $_.

From General Variables in perlvar

Here are the places where Perl will assume $_ even if you don't use it:

  • The following functions use $_ as a default argument:

    • abs, alarm, chomp, chop, chr, chroot, cos, defined, eval, evalbytes, exp, fc, glob, hex, int, lc, lcfirst, length, log, lstat, mkdir, oct, ord, pos, print, printf, quotemeta, readlink, readpipe, ref, require, reverse (in scalar context only), rmdir, say, sin, split (for its second argument), sqrt, stat, study, uc, ucfirst, unlink, unpack.
  • All file tests (-f , -d ) except for -t , which defaults to STDIN. See -X

  • The pattern matching operations m//, s/// and tr/// (aka y///) when used without an =~ operator.

  • The default iterator variable in a foreach loop if no other variable is supplied.

  • The implicit iterator variable in the grep() and map() functions.

  • The implicit variable of given().

  • The default place to put the next value or input record when a <FH>, readline, readdir or each operation's result is tested by itself as the sole criterion of a while test. Outside a while test, this will not happen.

  • $_ is by default a global variable.

As you can see, it is available nearly everywhere and it is indeed used a lot. Note that the perlvar page describes a whole lot more of similar variables, many of them good to know about.

Here is an example. Consider that we read lines from a file, want to discard the ones which have only spaces or start with # (comments), and for others want to split them by spaces into words.

open my $fh, '<', $file  or die "Can't open $file: $!";

while (<$fh>) 
{
    next if not /\S/;
    next if /^\s*#/;

    my @words = split;

    # do something with @words ...
}

Let's see how many uses of $_ are in the above example. Here is an equivalent program

while (my $line = <$fh>) 
{
    next if not $line =~ m/\S/;    # if not matching any non-space character
    next if $line =~ m/^\s*#/;     # if matching # after only (possible) spaces

    my @words = split ' ', $line;  # split $line by ' ' (any white space)

    # do something with @words ...
}

Compare these two

  • the filehandle read <$fh> in the while condition assigns to $_, then available in the loop.

  • regular expression's match operator by default works on $_. The m itself can be dropped.

  • split by default splits $_. We also use the other default, for the pattern to split the string by, which is ' ' (any amount of any white space).

  • once we do $line = <$fh> the deal with $_ is off (it is undefined in the loop) and we have to use $line everywhere. So either do this or do while (<$fh>) and use $_.

To illustrate all this a bit further, let us find the longest capitalized word on each line

use List::Util 'max';

my $longest_cap = max map { length } grep { /^[A-Z]/ } @words;

The grep takes the list in @words and applies the block to each element. Each element is assigned to $_ and is thus available to the code inside the block as $_. This is what the regex uses by default. The ones that satisfy the condition are passed to map, which also iterates assigning them to $_, what is of course the default for length. Finally max from List::Util picks the largest one.

Note that $_ is never actually written and no temporary variable is needed.

Here is some of the relevant documentation. The I/O Operators in perlop discusses while (<$fh>) and all manner of related things. The regex part is in Regexp Quote-Like Operators in perlop and in perlretut. Also have a look at split.


Defaults are used regularly and to read code written by others you must understand them. When you write your own code though you can choose whether to use $_ or not, as one can always introduce a lexical variable instead of it.

So, when to use $_ as default (which need not be written) and when not to?

Correct use of defaults, $_ in particular, can lead to clearer and more readable code. What generally means better code. But it is quite possible to push this too far and end up with obscure, tricky, and brittle code. So good taste is required.

Another case is when some parts of the code benefit from having $_ for their defaults while at other places you then have to use $_ explicitly. I'd say that if $_ is seen more than once or twice in a section of code it means that there should be a properly named variable instead.

Overall, if in doubt simply name everything.

like image 83
zdim Avatar answered Mar 16 '23 23:03

zdim