views:

355

answers:

8

In Perl, one can often avoid using control blocks, like this:

print "$_\n" foreach(@files);

instead of:

foreach(@files){
  print "$_\n";
}

How does this syntax work in the following, more complex case:

die("Not a file: $_") unless -f $_ foreach(@files);

It gives me a syntax error. I'm not trying to write obfuscated code, it's just an unimportant part in the program, and so I want to express it as concisely as possible.

SUMMARIZED ANSWERS:

I can accept only one answer as the accepted answer, but I like the following ones from Chris and Jon best.

This one uses foreach as I intended, but without the syntax error:

-f or die "Not a file: $_" foreach @files;

And the following one is at least as good. I like that die is at the beginning of the statement because that's what the reader's attention should be directed toward:

die("Not a file: $_") for grep {!-f} @files;
+6  A: 

Well, you may not be intending to write obfuscated code, but I'd say that you're certainly trying to.

Would two lines (or even a block on one line, like Brent.Longborough suggests) instead of one be so bad? Honestly, this is the reason I generally hate trying to debug/edit other peoples' perl code, a large number of people that write in perl seem to be obsessed with doing almost everything in the most "clever" way possible, instead of doing it in a way that's easy to understand for someone else reading.

Chad Birch
+1. I never understood why "clevver == in just one line" for some people.
innaM
I think some of the examples (like the one using `grep`) are "clever", but not because they're just one line. They're clever because they're just one line, but clearly show the meaning. And it looks nice - nested parenthesis and brackets on one line looks bad (in my opinion (except in Lisp (haha))).
Chris Lutz
+3  A: 

If you are not trying to write obfuscated code, then you should not try to write it like this. You are taking something that should be simple and making it hard to understand.

gpojd
What the hell is obfuscated about this? How would you write it?
Svante
I agree with Harleqin - several answers on this page show that there are ways to write this that are both a) clear and b) one line.
Chris Lutz
I was responding to his comment saying "I'm not trying to write obfuscated code." His attempt was obfuscated as defined by Webster: "to be evasive, unclear, or confusing". The responses that were submitted when I posted were unclear and confusing, while some examples that were posted later look ok.
gpojd
+10  A: 

You could either use @Brent.Longborough's answer, or if you really want postfix, do:

do { die("Not a file: $_") unless -f $_ } foreach(@files);

However, I agree with the others, just because this is "an unimportant part" doesn't mean that concise is better. Readability counts.

Adam Bellaire
How is it not readable? How would you prefer to write it?
Svante
I didn't say it's "not readable." However, I do assert that it is *less* readable to use chained postfix control structures. That is of course subjective. The point is that the OP didn't say he was trying to maximize readibility, but that it should be "concise" because it was "unimportant."
Adam Bellaire
+5  A: 

If the error test is the primary point of this code, it might make sense for it to have the prime location at the beginning of the line. A slight improvement would be to use grep:

die("Not a file: $_") for grep {!-f} @files;

But if you plan on looping through the files for some other reason in that part of the code, it would be better to add it to the body of the loop.

Jon Ericson
A: 

Damn, Jon just beat me to grep.

But I have a larger question: how is it not important if you're actually going to bail out if you find some non-files in your array? (As opposed to, say, removing those items, warning the user and then processing the rest of the list.) I would think that killing the whole shebang is a reasonably important part of the program.

In any case, you can't do exactly what you want with postfix modifiers since you can only have one thing on either side of them. So you can't have both the unless and the foreach. From the top of the relevant bit of perldoc perlsyn:

Any simple statement may optionally be followed by a SINGLE modifier, just before the terminating semicolon (or block ending).

Telemachus
Yeah. If it were just a print, I'd say the traditional notation is better. But die probably ought to be the first token on a line if possible.
Jon Ericson
+8  A: 

Just to be Perlish (TMTOWTDI) you can use logic short-circuiting:

-f or die "Not a file: $_" foreach @files;

Tested on OS X and works.

As a side note, -f or die looks like a lot of common open() or die constructs I see in Perl, and still (I think) shows the intention of the line (to die under certain conditions).

Chris Lutz
Very neat. ++ and hooray for the Swiss Army Chainsaw!
Brent.Longborough
I like it. The parallel with open() or die() is a bit off, since the purpose of open() is usually to open a file not die(). But if you think of the purpose of the above code is to test the existence of a file, the parallel is accurate. Tough call, but I think I like yours a touch more. ;-)
Jon Ericson
A: 
innaM
A better, but less shocking, quote from the linked article: "Alternatively, always code and comment in such a way that if someone a few notches junior picks up the code, they will take pleasure in reading and learning from it." -- http://c2.com/cgi/wiki?CodeForTheMaintainer
Jon Ericson
A: 

You're thinking too hard. Here it is on one line with no acrobatics:

 foreach ( @files ) { die( "Not a file!" ) unless -f }

You might play around with the stuff inside the block to golf it down, but removing the parens and the braces isn't helping you any, and is probably going to confuse the next programmer who has to look at it.

You probably have something more complicated though, and this is only an example. In the real world, it gets even easier:

not_a_file_die_die_die( \@files );

You then move all the complicated stuff to a subroutine. The real trick is to make the idea and intent concise, not the code that implements the idea. The mechanics really don't matter in many cases; you care more about the result. In those cases, don't sweat the mechanics.

brian d foy