Re: foreach loop and creating files with "$_"
by xyzzy (Pilgrim) on Jul 22, 2014 at 03:58 UTC
|
my $file = "file"; # why not...
my $temp = "temp"; # makes sense if you later want to use
# some other basename for your sequence of files
foreach (1..5){
open $file, '>', "$temp$_"; # you just turned $file from a string in
+to a filehandle...
...
}
In other words your assignment in the first line does nothing since the value gets clobbered when you use open
On to your question. I quickly glanced at the node and the author is basically saying that sometimes it is unclear what $_ is supposed to represent. Whether or not this is the case depends on the context that you use it in. For instance: foreach (@lines) {
$_ = uc; # ALL CAPS WOOOOOO
s/$/!!!/; # EVERY LINE IS AN EXCLAMATION!!!
print;
}
It's fairly obvious that each operation of the loop is performed on each line in @lines. However, this may not be the case if you have a longer, more complex loop, and will not work at all if you have nested loops:my @timesTable;
foreach my $row (0..12) { #
foreach my $col (0..12) {
@timesTable[$row][$col] = $row * $col;
}
}
There are also times where I will take advantage of $_ to perform a bunch of operations on a single variable in a sort of pseudo-loop:for ($leetString) { # "loops" only once
s/very/uber/g;
tr/astloe/457103/;
s!w!\\/\\/!g;
}
You didn't hear it from me, but the best part about Perl is that once you understand how the lingo works, you can use it any way you damn please. Unless you work with people who won't understand what you're saying, and you want them to understand what you're saying. Then you have turn to these annoying things called "Best Practices".
$,=qq.\n.;print q.\/\/____\/.,q./\ \ / / \\.,q. /_/__.,q..
Happy, sober, smart: pick two.
| [reply] [d/l] [select] |
|
|
i didnt even catch the mistake at the beginning, i was just excited it worked i guess, glad you noticed tho loool xD
| [reply] |
|
|
for (1..$num) {
open my $fh, '>', sprintf "temp%02d",$_; # temp01, temp02, etc.
...
}
Consider doing this if you plan to have more than 9 temp files and you want to keep them in numerical order. %02d will pad an integer with leading zeroes until it's two digits long. For more information, consult perldoc -f sprintf. You can even use a base-10 logarithm before the loop to figure out how many leading zeroes you would need, then insert that number into your format string.
EDIT: forgot that $_ is not implied with sprintf
$,=qq.\n.;print q.\/\/____\/.,q./\ \ / / \\.,q. /_/__.,q..
"My life is like my typing: fast and full of mistakes."
| [reply] [d/l] [select] |
Re: foreach loop and creating files with "$_"
by Athanasius (Archbishop) on Jul 22, 2014 at 03:39 UTC
|
Hello james28909,
Your use of $_ to generate the filenames “temp1”, “temp2”, ... “temp5” looks fine to me. There is, in general, nothing wrong with using $_. On the contrary, $_ is one of Perl’s strengths, because it facilitates the writing of concise, elegant code.
In the article you reference, apotheon recommends this rule of thumb for $_: If you have to use it explicitly, use something else instead. So far as I can see (I’ve only skimmed the article), the only justification given for this opinion is that:
a lot of people find $_ ugly and even obfuscatory.
Possibly true, but then they are people who don’t know and use Perl! Perl is, by design, an atypical language, so its idioms and byways are often unintuitive at first, but unfamiliar should never be mistaken for ugly. As apotheon notes, people who find Perlish idioms ugly sometimes avoid Perl itself for that reason. IMHO that is not necessarily a bad thing.
Hope that helps,
| [reply] [d/l] [select] |
|
|
When using $_ keep in mind that it may change when you're not expecting it to. For example, if a sub gets called between setting $_ and using it, there's a fair chance that $_ will have changed. apotheon's rule of thumb is a good defence against that. Using a well named variable also has the huge advantage that it conveys intent which makes code more robust, easier to understand and easier to maintain.
In the OP's code there is pretty much no chance that $_ is going to change unexpectedly as it stands, but for clarity a loop variable helps:
for my $fileIdx (1 .. 5) {
my $fileName = "$temp$fileIdx";
open $file, '>', fileName or die "Failed to create fileName: $!\n
+";
...
}
Perl is the programming world's equivalent of English
| [reply] [d/l] |
|
|
a lot of people find $_ ugly and even obfuscatory.
Possibly true, but then they are people who don’t know and use Perl! Perl is, by design, an atypical language, so its idioms and byways are often unintuitive at first, but unfamiliar should never be mistaken for ugly. As apotheon notes, people who find Perlish idioms ugly sometimes avoid Perl itself for that reason. IMHO that is not necessarily a bad thing.
I concur. And I'll submit that $_ is actually quite intuitive -- it's just other programming languages that are unintuitive, unfamiliar and (arguably) unnatural in this regard.
For me, $_ is simply the current topic that's being talked about. Like in natural languages, sometimes you leave it out entirely, since it's clear from the context what's being meant; sometimes you merely say "this" or "it" (which is how I read $_). Perl doesn't go quite as far as natural languages where you can have several of these at once, but on the other hand, unlike natural languages, Perl cannot afford to be ambiguous ("Bill met Bob. They talked, and he gave him back the book" is fine; the same thing in Perl wouldn't be).
Still, having one "topic" is better than having none, as most programming languages do. Natural languages are intuitive, after all, and we're all familiar with them.
| [reply] |
|
|
| [reply] |
|
|
|
|
a lot of people find $_ ugly and even obfuscatory... Possibly true
It's about as true as the statement "Chinese language is ugly and obfuscatory". I mean, a lot of people find things like "舍阿奈比山是突尼西亞最高峰" completely unreadable... right?
| [reply] |
|
|
actually perl's wild looking code is what brought me to perl, i like its hacky script look lol
| [reply] |
Re: foreach loop and creating files with "$_"
by wjw (Priest) on Jul 22, 2014 at 03:51 UTC
|
Take a look at $_ in perlvar. Frankly, I don't hesitate to use $_. But then most of my code is fairly straight forward procedural code without much scoping challenge. I am sure someone here has run into an issue or two making use of $_, but I certainly have not.
I personally don't like the 'visual' of $temp$_, so would handle it differently, but I don't see anything functionally wrong with it.
...the majority is always wrong, and always the last to know about it...
Insanity: Doing the same thing over and over again and expecting different results...
A solution is nothing more than a clearly stated problem...otherwise, the problem is not a problem, it is a facct
| [reply] [d/l] |
|
|
just as an example, how would you do it differently if i might ask? :)
| [reply] |
|
|
my $file = "file";
my $temp = "temp";
foreach (1..5){
open $file, '>', "$temp" . "$_";
print $file "THIS IS DATA";
}
or
my $file = "file";
my $temp = "temp";
foreach my $end (1..5) {
open $file, '>', "$temp" . "$end";
print $file "THIS IS DATA";
}
(not tested)
Personal preference only...
...the majority is always wrong, and always the last to know about it...
Insanity: Doing the same thing over and over again and expecting different results...
A solution is nothing more than a clearly stated problem...otherwise, the problem is not a problem, it is a facct
| [reply] [d/l] [select] |
|
|
|
|
use Path::Tiny qw/ cwd path tempfile /;
## in cwd
path( "temp$_" )->spew("THIS IS DATA") for 1 .. 5;
## in $TMP directory
tempfile( 'tempjamesXXXX' )->spew("THIS IS DATA") for 1 .. 5;
| [reply] [d/l] |
Re: foreach loop and creating files with "$_"
by Anonymous Monk on Jul 22, 2014 at 03:59 UTC
|
| [reply] |
Re: foreach loop and creating files with "$_"
by james28909 (Deacon) on Jul 22, 2014 at 04:51 UTC
|
open my $data, '<', "data.bin";
binmode($data);
read $data, my $buf, 0x1000000;
my $copy = "copy";
foreach (1..5){
open my $file, '>', "$copy$_";
binmode($file);
print $file $buf;
}
thats so easy now that i think about it. hell i use the foreach loop alot in some other code i have. its a wonder i didnt think about this before now, anyway thanks for the input :)
you could even make it read in so many chunks at a time or split up the file in other words (why? i dunno):
open my $data, '<', "data.bin";
binmode($data);
my $chunk = "chunk";
foreach (1..5){
open my $file, '>', "$chunk$_";
binmode($file);
read $flash, my $buf, 0x200;
print $file $buf;
}
| [reply] [d/l] [select] |
Re: foreach loop and creating files with "$_"
by AnomalousMonk (Archbishop) on Jul 22, 2014 at 16:46 UTC
|
my $file = "file";
my $temp = "temp";
foreach (1..5){
open $file, '>', "$temp$_";
print $file "THIS IS DATA";
}
Whatever you may think of the use of $_ this code doesn't compile under strictures because $file is not undefined. Quoth the open docs (emphasis added):
If FILEHANDLE is an undefined scalar variable (or array or hash
element), a new filehandle is autovivified, meaning that the
variable is assigned a reference to a newly allocated anonymous
filehandle. Otherwise if FILEHANDLE is an expression, its value
is the real filehandle. (This is considered a symbolic
reference, so "use strict "refs"" should *not* be in effect.)
c:\@Work\Perl\monks\james28909>perl -wMstrict -e
"my $file = 'file';
my $temp = 'temp';
;;
foreach (1..5){
open $file, '>', qq{$temp$_};
print $file 'THIS IS DATA';
}
"
Can't use string ("file") as a symbol ref while "strict refs" in use a
+t -e line 1.
(Talk about rearranging the deck chairs on the Titanic! :)
| [reply] [d/l] [select] |
|
|
yeah i had caught that earlier lol. i removed the first reference to the "file" and added "my $file" in the loop.
and thanks to everyone for the valuable input.
need more input hehe
| [reply] |
Re: foreach loop and creating files with "$_"
by locked_user sundialsvc4 (Abbot) on Jul 22, 2014 at 12:06 UTC
|
I’d go with foreach my $var (1..5) every time, for the very same reason that “I don’t like to see the same global variable-name being used again and again.” Especially not, as in this case, one that you can’t see.
Okay, so it works okay now. Goody,goody, but then someone comes along and needs to make a truly-slight change ... which just happens to consist of some other control-structure that changes the meaning and value of $_. Now, they have to dance-around your program, making a bunch of source-code changes (entirely unrelated to what they wanted to do ...), just to do what you could well have done the first time. (And, to keep things realistic, let’s say they inadvertantly miss just one thing ...) Meh. That sort of thing is “just not worth the clever.”
Keep it simple ... keep it maintainable. I’m not laying-down any sort of commandment here, but it is trivially easy (as shown) to create a very nice, named, locally-scoped variable, associated with the loop and existing only within its scope, that contains the value of the loop index. That’s one of Perl’s nicest, most pragmatically useful features. (As is $_, yes, in small doses ...)
| |
|
|
I think the biggest maintainability problem with $_ is accepting it as a default without using it. We are forced to remember every place it can be used in this way.
| [reply] |