Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

and this or that

by mkmcconn (Chaplain)
on Feb 05, 2001 at 22:45 UTC ( [id://56469]=perlquestion: print w/replies, xml ) Need Help??

mkmcconn has asked for the wisdom of the Perl Monks concerning the following question:

Fellow-seekers of Perlish righteousness, lately I have been dabbling with using and and or in places for which I cannot prove precedence among the fathers.

Tell me, am I sinning to use and and or to combine statements as follows?

for my $next (@ARGV){ opendir(PWD,"$next") and my @files = readdir PWD or die "Open \"$_\" failed: $!"; closedir PWD or die $!; print "$_\n" for @files; }

Especially, this seems useful in testing regular expressions as in this recent example, where ...

s/test/whatever/ and print or print;

...will print the substitution if the match succeeds, or print the unmodified string if it fails.

Are there problems with this style? Is it testing what I think it is? Is it always going to be reliable, or will it break under some conditions? Is it more common to do this than I had thought?
mkmcconn

Replies are listed 'Best First'.
Re: and this or that
by jeroenes (Priest) on Feb 05, 2001 at 22:57 UTC
    And & or have the lowest priority possible, according to perlop, so you are safe. The last few from the row:
    nonassoc list operators (rightward) right not left and left or xor
    You see, the list operator is even higher, and that is the most tricky one out there.

    I wouldn't use and with substitution, though. Just:

    s/test/somestuff/; print;
    does the job cleaner: only one print.

    Hope this helps,

    Jeroen
    "We are not alone"(FZ)
    Update: lemming showed me a typo. Fixed. Thanx!

      Thank you for the reply jeroenes.
      (BTW, the first block in my question has a mistake, saying "$_" where it should say "$next".)
      You said
      I wouldn't use and with substitution, though. Just:

      s/test/somestuff/; print;
      does the job cleaner: only one print.

      You're right about that. Would the following be a better illustration of the advantage I perceive?

      s/^(\d+)/("0"x(8-length).$1)/xe and print or s/^(\w)/("\x20"x(8-length).$1)/xe and print for @ARGV;
      Suppose that @ARGV is a combination of digits and words, all digits get zero-padding and all words are padded by space. Anything that fails both matches should be discarded.

      Update:
      Very well then, jeroenes - I will follow the tradition
      And thanks again for the replies :-) mkmcconn

        Even than:
        for (@ARGV){ print if s/first/somet/ or s/second/somet/; }
        Would use only one print ;-).

        Jeroen
        "We are not alone"(FZ)

Re: and this or that
by dws (Chancellor) on Feb 05, 2001 at 23:40 UTC
    Your precedence problem goes away with a little untangling. Move the error handling for opendir() in closer to the call, rather than out past the readdir(). Here's I'd code it.
    for my $next (@ARGV){ opendir(PWD, "$next") or die "$next: $!"; my @files = readdir(PWD) or die "$next: $!"; closedir(PWD); print join("\n", @files), "\n"; }
    (Updated to add error handling after readdir(), too.)

    Or, if you really want to use precedence, and if you want to ignore non-directories in @ARGV, consider

    for my $next (@ARGV) { opendir(PWD, "$next") and do { my @files = readdir(PWD) or die "$next: $!"; closedir(PWD); print join("\n", @files), "\n"; } }
      for my $next (@ARGV) { opendir(PWD, "$next") and do { my @files = readdir(PWD) or die "$next: $!"; closedir(PWD); print join("\n", @files), "\n"; } }
      TIMTOWDI. I personally find this a little clearer, and is no less idiomatic:
      foreach my $next (@ARGV) { if (opendir(PWD, "$next")) { my @files = readdir(PWD) or die "$next: $!"; closedir(PWD); print join("\n", @files), "\n"; } }
      While using and and do like that is only slightly less clear than using a true 'if' block, it is slightly less clear than using a true 'if' block. :)
Re: and this or that
by MeowChow (Vicar) on Feb 06, 2001 at 00:33 UTC
    Usually if I want to do something like this, I use both the low-precedence and high-precedence operators, to explicitly and obviously indicate what is happening, as follows:
    opendir(PWD,"$next") && my @files = readdir PWD or die "Open \"$_\" failed: $!";
    A side note: As a matter of good form, I don't declare lexically scoped variables within subexpressions, and especially not within conditionally executed ones, like you did with @files. In this specific example, I would not combine the readdir and openddir in one line.

    Your second example I would seperate into two statements as jeroenes suggested above, but you can also do

    s/test/whatever/, print;
    if you're really itching to put it all on one line. Or, if you prefer:
    s/test/whatever/ => print;
       MeowChow                                               
                    print $/='"',(`$^X\144oc $^X\146aq1`)[-2]
      Aside from the minor problem of using $_ where you mean to use $next, there are two problems with
      opendir(PWD,"$next") && my @files = readdir PWD or die "Open \"$_\" failed: $!";

      First, you waste future readers' time. The few seconds you've saved by writing the above rather than

      opendir(PWD,$name) or die "$name: $!"; my @files = readdir(PWD) or die "$name: $!";
      Have just eclipsed by N x "what's this? uh.. oh, I see". Better, in my humble opinion, to write straightforward code. Sure, you have code "or die" twice, but in the scheme of things, that's a really minor nit.

      Second, in the unikely event that opendir() succeeds and readdir() fails, you're presenting a misleading diagnostic.

        Which is exactly why I said:

        "In this specific example, I would not combine the readdir and openddir in one line. "

        I was re-cycling his example code simply to make another point about operator precedence.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://56469]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (2)
As of 2024-04-20 05:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found