Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Re: No warning when assiging to a variable

by McA (Priest)
on Aug 14, 2013 at 18:52 UTC ( [id://1049461]=note: print w/replies, xml ) Need Help??


in reply to No warning when assiging to a variable

Hi,

just a guess: At compile time the compiler knows that the expression in the if statement will always evaluate to a constant 2, the if clause is probably meaningless, you get a warning. In the case of if ($foo = $bar) it may be intended, but anyway: The compiler can't evaluate the if clause to a constant as $bar can be true or false, so the conditional if may make sense.

Best regards
McA

Replies are listed 'Best First'.
Re^2: No warning when assiging to a variable
by afoken (Chancellor) on Aug 16, 2013 at 19:38 UTC

    Let's have a look at what gcc does:

    /tmp>cat gcc-warn-assign.c int main(void) { int i,x,y; i=x=y=0; /* unintentional assignment inside if condition */ if (x=42) i++; if (x=y) i++; /* intentional assignment inside if condition, marked with ext +ra parentheses */ if ((x=42)) i++; if ((x=y)) i++; return i; } /tmp>gcc -Wall -pedantic gcc-warn-assign.c gcc-warn-assign.c: In function ‘main’: gcc-warn-assign.c:6:2: warning: suggest parentheses around assignment +used as truth value gcc-warn-assign.c:7:2: warning: suggest parentheses around assignment +used as truth value /tmp>gcc --version gcc (GCC) 4.5.2 Copyright (C) 2010 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There i +s NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PUR +POSE. /tmp>

    So, what do we see here?

    (Ignore i and i++, it's just dummy code.)

    Possibly unintentional assignments inside if conditions cause warnings, no matter what is on the RHS of the assignment operator. The RHS may be a constant, or any other expression. It does not matter, and it should not matter.

    If you want to write "especially clever" code, you still can assign inside an if condition without warnings, but you must wrap the assignment in semi-redundant parentheses to make your intention -- you want to test the truth of the result of the assignment -- clear to gcc. And the code is still compatible with other C compilers that do not know the extra parentheses trick, they just ignore the redundant parentheses.

    I think Perl with warnings enabled should behave the same: Warn if a variable is assigned anything, constant or not, inside the condition of if and friends, because it is likely a bug. And don't warn only if the assignment has extra parentheses indicating someone wanted to write "especially clever" code.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

      Hi Alexander,

      Perl is not C.

      Let's look at a common idiom in Perl:

      while(my $line = <>) { do_something($line); }

      This is an assignment in a conditional operator. It does fortunately not emit a warning. Let's look at a more or less equivalent code in C:

      #include <stdio.h> #include <stdlib.h> int get_val(void); int main(void) { int i, x, y; i = x = y = 0; while (x = get_val()) { i++; printf("in loop\n"); if(i == 1) { exit(1); } } return i; } int get_val(void) { return(1); }

      Compiled with LANG=C gcc -Wall -pedantic -o warning warning.c it does emit the following:

      warning.c: In function 'main': warning.c:11: warning: suggest parentheses around assignment used as t +ruth value

      IMHO, it proves: Perl is not C, C is not Perl. C is a compiled language. Perl is a interpreted language.

      In my opinion, the above Perl idiom should not emit a warning like C does.

      Best regards
      McA

      P.S.: A ++ for your comparison.

        Perl is not C.

        No, but it borrows several ideas and a lot of syntax from C.

        Let's look at a common idiom in Perl:
        while(my $line = <>) { do_something($line); }

        Yes, this is a common idiom, but it differs from a simple, probably accidental assignment by introducing my. I would consider this as a clear marker for an intentional assignment, like the semi-redundant parentheses that gcc uses.

        So, the rules for assignment-in-condition warnings should probably be as following:

        • if ($var=anything) and while ($var=anything) should warn, because the assignment is probably unintentional, i.e. a possible bug.
        • if (($var=anything)) and while (($var=anything)) should not warn, because the assignment is marked as intentional by using extra parentheses.
        • if (my $var=anything) and while (my $var=anything) should not warn, because the assignment is marked as intentional (for use in the following block) by using my $var instead of a simple $var.
        • if (local $var=anything) and while (local $var=anything) should not warn, for the same reason.
        • if (our $var=anything) and while (our $var=anything) look really ugly. our does not belong there. But that's a different problem, so Perl should not warn, for the same reason as with my and local.

        Of course, the same rules would apply to elsif, unless and until; and of course also to assignments to arrays and hashes.

        IMHO, it proves: Perl is not C, C is not Perl. C is a compiled language. Perl is a interpreted language.

        And it would not hurt to adopt the idea of testing for unintentional assignments. Perl already has code to check for unintentional assignments of constants, all that would be needed is to expand it to check for unintentional assignments of anything else. This is what gcc does, this is what mikeraz expects, and this is what I consider a good thing.

        In my opinion, the above Perl idiom should not emit a warning like C does.

        It would not, because of my. Adding semi-redundant parentheses (i.e. while (($line=<>))) would silence the warning, too.

        The similar while (<>) implicitly assigns to $_, and this assignment is intentional, so no warning here.

        My little set of rules still allows stupid code like the following:

        if (($zero=0)) { do_something($zero); # never } if (my $one=1) { do_something($one); # always } while (($two=2)) { do_something($two); # for ever } while (my $empty='') { do_something($empty); # never }

        It seems the existing check for a constant assignment, intentional or not, is still useful.

        That check should come first. Only if that check does not issue a warning, Perl should check for the intention markers (semi-redundant parentheses, my, local, our) around an assignment, and issue a similar warning if they are missing.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (6)
As of 2024-03-19 09:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found