Home > other >  Why comparison operator not working properly and Block of operator 'ne' is working
Why comparison operator not working properly and Block of operator 'ne' is working

Time:06-03

I have some strings I am taking from the command line as an argument, I required to run the block, if particular argument has been passed or else it shows the print statement and exit.

I am using two blocks where in first one I am using 'ne' operator to check if strings is not equal to desired strings then exiting the program and 'eq' operator to check if string passed is equal then execute the code.

Below is my code snippet:


 my $number_args = $ #ARGV   1;
 if ($number_args ne 2) {
         print "Usage: perl testAutomation.pl <ExcelSheetName.xlsx> <Production/Development/All>.\n";
         exit;
 }
 my $tstRunSheet = $ARGV[0];
 my $tstRunType = $ARGV[1];

 if ($tstRunType ne 'Development' || $tstRunType ne 'Production' || $tstRunType ne 'All') {
         print "Usage: perl testAutomation.pl <ExcelSheetName.xlsx> <Production/Development/All>.\n";
         exit;
 }
 elsif($tstRunType eq 'Development' || $tstRunType eq 'Production') {
         ($result1, $result2, $result3, $result4, $result5, $result6, $result7, $result8) = & getXlxsDetails($tstRunSheet, $tstRunType);
 }

When I am giving proper string as required in my elsif block still it is running the if block.

output

Output

CodePudding user response:

The issue comes from this line:

if ($tstRunType ne 'Development' || $tstRunType ne 'Production' || $tstRunType ne 'All') {

This condition is always true: if $tstRunType is Development, then it's not Production, and $tstRunType ne 'Production' returns true (and similarly for all possible values of $tstRunType).
Instead, you should write:

if ($tstRunType ne 'Development' && $tstRunType ne 'Production' && $tstRunType ne 'All') {

Then, if $tstRunType is one of Development, Production or All, the corresponding ne test will return false, making the whole condition false.


You could also write this condition as:

my @run_types = qw(Development Production All);
if (!grep { $tstRunType eq $_ } @run_types) { ...

This way, you don't have to repeat 3 times a similar test and you can easily add new run types.

Or, using a regex to have a slightly more compact test:

if ($tstRunType !~ /^(Development|Production|All)$/) {

Also, note that my $number_args = $#ARGV 1; can be written simply as my $number_args = @ARGV;.

CodePudding user response:

Dada has given you the correct answer: Your logic is flawed.

my $x = 1;
if ($x != 0 || $x != 1)    # will always be true, no matter what $x is, because 0 != 1

But more than that, I think your structure is wrong. You should not begin by gathering all the valid options and check for lack of them. Go through and check all the options, and then have as a default behaviour the lack of a valid option. For example:

if ($type eq "Dev") {
    print "Dev things\n";
} elsif ($type eq "Prod") {
    print "Prod things\n";
} elsif ($type eq "All") {
    print "All things\n";
} else {
    print "Usage: ...:";
    exit;
}

Another design detail is your repetition of the usage message. You can put that in a sub.

sub usage {
    print "Usage: $0 <excel> <keywd>";
    exit;
}

For quick and easy use:

usage() if @ARGV != 2;

Note that you should not use ne for numerical comparisons. Study perldoc perlop to learn more. In your case, ne will try to cast the numbers 2 to a string, "2" and then perform "2" ne "2". A common mistake when confusing these operators is this:

my $word = "foo";
if ($word == "bar") {
    print "$word == 'bar'\n";
}

This will give us the very confusing output:

foo == 'bar'

Which is explained when we activate use warnings:

Argument "bar" isn't numeric in numeric eq (==) at bar.pl line 3.
Argument "foo" isn't numeric in numeric eq (==) at bar.pl line 3.
foo == 'bar'

What happens? Well, == assumes its both arguments are numbers, so it tries to cast the strings "foo" and "bar" to numbers. Which it fails to do, since neither of the strings begin with a number, or look like a number. So they are cast to 0, numerical zero. And 0 == 0 is true.

So what is wrong with using ne if it works? Well, in this case it works, but it can fail for comparisons such as " 2" eq "2", 2 eq "2.0", etc. Cases where the string values are different, even though the numerical values are the same.

Also note that you could use a call table to reduce the size of your if-structure.

my            
  • Related