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

This node falls below the community's threshold of quality. You may see it by logging in.

Replies are listed 'Best First'.
Re: This is why Perl is so frustrating
by FunkyMonk (Bishop) on Jul 29, 2009 at 18:07 UTC
    AM I MISSING A FUNDAMENTAL ASPECT OF LOGICAL OPERATIONS

    yes :-(

    ($file ne ".") or ($file ne "..")

    is always true. You want to process file when it's not-equal to '.' AND not-equal to '..':

    ($file ne ".") && ($file ne "..")

Re: This is why Perl is so frustrating
by MidLifeXis (Monsignor) on Jul 29, 2009 at 18:04 UTC

    Assume that $file eq '.'

    (($file ne ".") or ($file ne ".."))
    (('.' ne ".") or ('.' ne ".."))
    ((FALSE) or (TRUE))

    $file eq '..' is left as an exercise for the reader.

    In general, if you have ((X <> A) || (X <> B)) (unless you have a dualstate quantum variable of some sort), you will end up with (TRUE || FALSE), (FALSE || TRUE), or (TRUE || TRUE), all of which reduce to TRUE.

    Update: You may also want to see -X to test if a directory entry is actually a file that you can open.

    --MidLifeXis

    The tomes, scrolls etc are dusty because they reside in a dusty old house, not because they're unused. --hangon in this post

Re: This is why logic is so frustrating (was This is why Perl is so frustrating)
by ELISHEVA (Prior) on Jul 29, 2009 at 18:11 UTC

    If you wish to verify that "x" is neither one of two possibilities, then you have to verify that "x" is not "." and "x" is not "..".

    so ... what you want is

    if (($file ne ".") and ($file ne "..")) { ...

    Best, beth

      Yes, I remember this all from school and my c programming days. True or False is always true unelss the bit flips due to cosmic background radiation or the butterfly effect:
      http://xkcd.com/378/

        Another annoying possibility is interrupts/concurrency. I once had a case where

        if ($x && !$x) {...}
        was evaluating to true, two or three times per hour.

Re: This is why Perl is so frustrating
by GrandFather (Saint) on Jul 29, 2009 at 20:51 UTC

    A more concise and (possibly) clearer way to code the test is:

    for my $file (@filenames) { next if $file =~ /^\.\.?$/; ... }

    note too the early 'exit' from the current loop iteration to avoid a level of nesting and make flow clearer.


    True laziness is hard work
      $file =~ /^\.\.?$/
      Or $file =~ /^\.{1,2}$/ (which is easier to extend later if one decides also to treat ... and friends specially! :-) ).
Re: This is why Perl is so frustrating
by jrsimmon (Hermit) on Jul 29, 2009 at 18:09 UTC
    if (($file ne ".") or ($file ne ".."))

    Will always be true, because no single value of $file can ever match both "." and "..". So yes, you are missing a fundamental aspect of logical operations.

    Namely: For a given A != B, (!A or !B) == !(A && B), which will always be true for any single value.

    Update:
    Perhaps you should spend some time reading this article.

      Namely: For a given A != B, (!A or !B) == !(A && B), which will always be true for any single value.

      ow.

      You attached two conditions to (!A or !B) == !(A && B), but it's always true.

      You refer some non-existent "single value" because you meant to talk about (V != A) or (V != B).


      I believe you meant:

      (A or B)
      is equivalent to
      !(!A and !B)
      Because of that,
      (V != A) or (V != B)
      is equivalent to
      !( (V == A) and (V == B) )

      If A != B, the "and" is obviously false (since V can't have two different values at the same time), and the whole statement is therefore true.

        Yeah, I changed which side of the statement I was adding the A != B qualifier, didn't clean it up well. Thanks for clarifying it.
Re: This is why Perl is so frustrating
by toolic (Bishop) on Jul 29, 2009 at 18:08 UTC
    Could you elaborate on your problem? If you are trying to avoid the special directories named '.' and '..', don't you want the 'and' logical operator instead of 'or'?

    Keep in mind that readdir returns both files and all sub-directories, not just the specially-named ones. If you want to filter out all directories, you can use -X.

Re: This is why Perl is so frustrating
by jdporter (Paladin) on Jul 29, 2009 at 18:15 UTC
    substr outside of string at lane_changer.pl line 33.

    I don't see $position, $length, $value being defined. Do you have use strict; use warnings; at the top of your program?

    Even if those variables are defined somewhere in code you didn't show, it's hardly surprising that you'd get that error, since they haven't been set to values corresponding to the length of the current $line.

    Between the mind which plans and the hands which build, there must be a mediator... and this mediator must be the heart.
Re: This is why Perl is so frustrating
by VinsWorldcom (Prior) on Jul 29, 2009 at 18:16 UTC
    I'm not sure what you're trying to do - I'm guessing you want to skip the directories '.' and '..'. Assuming that, then I think you are "MISSING A FUNDAMENTAL ASPECT OF LOGICAL OPERATIONS".

    You need to 'and', not 'or'. The way it's written (or), first time through, $file = '.', which makes the first half of the if statement false. However, $file = '.', so it can't equal '..', which makes the second part of the if statement true ($file ne '..' <==, yes, that's correct, because $file = '.'). Now you OR 1 and 0 and get a true condition; thus execute the if statement.

Re: This is why Perl is so frustrating
by talexb (Chancellor) on Jul 29, 2009 at 20:48 UTC

    I would replace that rather clunky

    if (($file ne ".") or ($file ne "..")) {

    with the more elegant

    unless ( $file eq "." || $file eq ".." ) {

    because it reads more naturally. In fact, since parsing the file is the only thing that's happening inside the loop, I would just skip the file entirely with

    next if ( $file eq "." || $file eq ".." );

    There might be responses to my post for calls to make a regular expression out of this, but it's not really necessary.

    Alex / talexb / Toronto

    "Groklaw is the open-source mentality applied to legal research" ~ Linus Torvalds

      For me
      unless ($expression){ # do something }
      is never elegant. I'll always plump for
      if (not $expression){ # do something }
      especially if, as in this case $expression includes some boolean arithmetic. I do use it for early exits from loops though. I can read
      while (<$fh>){ next unless /\S/; # }
      without too much trouble (as long as it's simple).

      As soon as an expression has a not an and and an or in it I'm almost sure to get it wrong and it often points to a poor algorithm which some refactoring can fix. Either that or put it into sub so I can say

      if (work_to_do($args)){ # do some work }
      and test the living daylights out of it.

      Did I mention I've had awful trouble with boolean arithmetic? :-)

        We'll have to agree to diagree on this one. I find

        if ( !$boolean1 and !$boolean2 ) {
        harder to read, and therefore more difficult to comprehend, than
        unless ( $boolean1 or $boolean2 ) {
        I make this distinction because the original code was checking *two* conditions, not just one. I will agree that it's a saw-off when comparing
        if ( !$boolean ) {
        and
        unless ( $boolean ) {
        But for me, if I miss the tiny '!' character, then I have the logic backwards, which is a huge problem. I'm not going to miss the 'unless'.

        Alex / talexb / Toronto

        "Groklaw is the open-source mentality applied to legal research" ~ Linus Torvalds

Re: This is why Perl is so frustrating
by jwkrahn (Abbot) on Jul 29, 2009 at 19:49 UTC

    You are also missing a couple of fundamental aspects of readdir.   In order to get a file name readdir queries the file system and what returns is an actual file name with no newline or anything else added to it so using chomp is at best superfluous and at worst will damage the actual file name.   And if you want to open a file with that name you have to remember that it is in $testdir and not the current directory like you seem to think it is.

Re: This is why Perl is so frustrating
by Marshall (Canon) on Jul 30, 2009 at 11:31 UTC
    When you open a directory and read it, you get all the files in it. As you see "." and ".." are files in every directory. A directory is a file, so it could be that there are other sub-directories in your test directory.

    opendir(DIRHANDLE, $testdir) or die "couldn't open directory: $testdir +"; @filenames = grep {-f "$testdir/$_"} readdir(DIRHANDLE); closedir(DIRHANDLE);
    What the grep addition does is filter the ouput of readdir so that @filenames only winds up with filenames that are "normal files", ie, not directories. Meaning that "." and ".." and any other sub-dirs are excluded from the list! ergo, no need for the logic test on ne "." and ".."! Of course you already see that the filenames are just the raw names and the dir path needs to be prepended when you use those names, even in this grep.

    Perl grep is way cool and is often used to filter lists. If the last statement in the grep evaluates to "true" the input on right is passed to output on left.

    another point: no need to use . concatenation op in many string cases. Perl will interpolate a $var inside of double quotes (like die statement above) and -f "$testdir/$_", the quotes are needed otherwise Perl would think that this is a division.

Re: This is why Perl is so frustrating
by eggmatters (Initiate) on Jul 29, 2009 at 18:09 UTC
    "AM I MISSING A FUNDAMENTAL ASPECT OF LOGICAL OPERATIONS?"

    Apparently, this happens:
    $file = "."
    if ($file ne "." ) (evaluates to true) or ($file ne "..")
    (evaluates to false)
    false or true = true?
    I thought that was &&
      Yes I got it backwards. Argghhh. Now I am eating some crow. Just so you know, we're under a massive heatwave and I have very little sleep with a newborn. This all makes me cranky and irritable and dyslexic and dumb. Sorry but Thanks for the prompt and helpful replies!! Perl is ok again!!

      That would be the fundamental aspect of logical operations which you have missed.

      (A||B) evaluates to true if either A or B are true.
      (A&&B) evaluates to true if and only if (iff) A and B are both true.