Why a different result?

Discussion in 'Perl Misc' started by James, Mar 27, 2012.

  1. James

    James Guest

    Expect the same output, but differ. Why?

    use Data::Dumper;

    undef %o, %e;
    for $f (1..$N) {
    if ($f%2) { $o{$f}= -1 } else { $e{$f}=1 }
    }
    print Dumper \%o; print Dumper \%e;

    undef %o, %e;
    for $f (1..$N) {
    $f%2 ? $o{$f}= -1 : $e{$f}=1;
    }
    print Dumper \%o; print Dumper \%e;

    (output)

    $VAR1 = {
    '1' => -1,
    '3' => -1,
    '7' => -1,
    '9' => -1,
    '5' => -1
    };
    $VAR1 = {
    '8' => 1,
    '6' => 1,
    '4' => 1,
    '10' => 1,
    '2' => 1
    };
    $VAR1 = {
    '1' => 1,
    '3' => 1,
    '7' => 1,
    '9' => 1,
    '5' => 1
    };
    $VAR1 = {
    '8' => 1,
    '6' => 1,
    '4' => 1,
    '10' => 1,
    '2' => 1
    };

    James
     
    James, Mar 27, 2012
    #1
    1. Advertising

  2. James

    Tim McDaniel Guest

    In article <>,
    James <> wrote:
    >Expect the same output, but differ. Why?
    >
    >use Data::Dumper;
    >
    >undef %o, %e;
    >for $f (1..$N) {
    >if ($f%2) { $o{$f}= -1 } else { $e{$f}=1 }
    >}
    >print Dumper \%o; print Dumper \%e;
    >
    >undef %o, %e;
    >for $f (1..$N) {
    >$f%2 ? $o{$f}= -1 : $e{$f}=1;
    >}
    >print Dumper \%o; print Dumper \%e;


    It's helpful to post real programs that run, because then people can
    immediately copy and paste it, run "-MO=Deparse,-p", or whatnot.

    See the precedence table near the top of "man perlop".
    Assignment operators bind more loosely than ?:, so the second method
    is equivalent to

    ($f%2 ? $o{$f}= -1 : $e{$f}) = 1;

    Assignments return lvalues that you can assign to again, so on odd
    numbers $o{$f} gets assigned -1 and then it gets stomped with 1.

    You can see this with

    $ perl -MO=Deparse,-p -e '$f%2 ? $o{$f}= -1 : $e{$f}=1;'
    ((($f % 2) ? ($o{$f} = (-1)) : $e{$f}) = 1);
    -e syntax OK

    I'll add numbers (in a fixed-width font) to show the paren pairing:

    ((($f % 2) ? ($o{$f} = (-1)) : $e{$f}) = 1);
    123 3 3 4 43 2 1

    Personally, I don't use ?: much, partially because it can sometimes
    lead to too-complicated expressions, and partially because it can
    cause precedence problems like this. Parenthesizing liberally in ?:
    can be a good idea.

    --
    Tim McDaniel,
     
    Tim McDaniel, Mar 27, 2012
    #2
    1. Advertising

  3. James

    James Guest

    On Mar 27, 1:18 pm, (Tim McDaniel) wrote:
    > In article <>,
    >
    >
    >
    >
    >
    >
    >
    >
    >
    > James  <> wrote:
    > >Expect the same output, but differ. Why?

    >
    > >use Data::Dumper;

    >
    > >undef %o, %e;
    > >for $f (1..$N) {
    > >if ($f%2) { $o{$f}= -1 } else { $e{$f}=1 }
    > >}
    > >print Dumper \%o; print Dumper \%e;

    >
    > >undef %o, %e;
    > >for $f (1..$N) {
    > >$f%2 ? $o{$f}= -1 : $e{$f}=1;
    > >}
    > >print Dumper \%o; print Dumper \%e;

    >
    > It's helpful to post real programs that run, because then people can
    > immediately copy and paste it, run "-MO=Deparse,-p", or whatnot.
    >
    > See the precedence table near the top of "man perlop".
    > Assignment operators bind more loosely than ?:, so the second method
    > is equivalent to
    >
    >     ($f%2 ? $o{$f}= -1 : $e{$f}) = 1;
    >
    > Assignments return lvalues that you can assign to again, so on odd
    > numbers $o{$f} gets assigned -1 and then it gets stomped with 1.
    >
    > You can see this with
    >
    >     $ perl -MO=Deparse,-p -e '$f%2 ? $o{$f}= -1 : $e{$f}=1;'
    >     ((($f % 2) ? ($o{$f} = (-1)) : $e{$f}) = 1);
    >     -e syntax OK
    >
    > I'll add numbers (in a fixed-width font) to show the paren pairing:
    >
    >     ((($f % 2) ? ($o{$f} = (-1)) : $e{$f}) = 1);
    >     123      3   3         4  43         2    1
    >
    > Personally, I don't use ?: much, partially because it can sometimes
    > lead to too-complicated expressions, and partially because it can
    > cause precedence problems like this.  Parenthesizing liberally in ?:
    > can be a good idea.
    >
    > --
    > Tim McDaniel,


    Thanks. So parenthesizing individual expressions is the key.
    ($f%2) ? ($o{$f}= -1) : ($e{$f}=1) ;

    James
     
    James, Mar 27, 2012
    #3
  4. James

    Tim McDaniel Guest

    In article <>,
    Ben Morrow <> wrote:
    >
    >Quoth James <>:
    >> $f%2 ? $o{$f}= -1 : $e{$f}=1;

    >
    >?: binds tighter than =, so this is equivalent to
    > ($f % 2 ? $o{$f} = -1 : $e{$f}) = 1;

    ....
    >You can also use and...or, but only if you are certain the 'if' part
    >will always return a true value:
    >
    > $f % 2 and $o{$f} = -1 or $e{$f} = 1;


    It took me a minute to figure out that you meant that the *then* part
    must always return true. (If the "if" part always returned true,
    there'd be no need for a conditional!) You make a good point. Indeed,

    $f % 2 and $o{$f} = 0 or $e{$f} = 0;

    would set both %o and %e for odd numbers.

    $f % 2 and ($o{$f} = 0, 1) or $e{$f} = 0;

    looks odd and fragile, and is no improvement over a parenthesized ?: .

    The idiom works much more reliably in Bourne-like shells, because
    commands' boolean value is based on their exit code, not usually the
    arithmentic result of an operation:

    (( f % 2 )) && echo "$f is odd" || echo "$f is even"

    --
    Tim McDaniel,
     
    Tim McDaniel, Mar 27, 2012
    #4
  5. James

    Uri Guttman Guest

    >>>>> "TM" == Tim McDaniel <> writes:

    TM> Personally, I don't use ?: much, partially because it can sometimes
    TM> lead to too-complicated expressions, and partially because it can
    TM> cause precedence problems like this. Parenthesizing liberally in ?:
    TM> can be a good idea.

    then you are thinking incorrectly about ?:. it is an expression and not
    meant for side effects. = is an assignment and a side effect. if you
    just use ?: to select one of two expressions it generally works well
    with no precedence issues. and it is usually cleaner than the longer
    if/else with redundant assignments. in fact if the lvalue is more then a
    variable then the ?: will be much cleaner than an if/else and less prone
    to bugs. when you have redundant code, you have to make sure both parts
    are the same, you need to change both if one is changed, and the reader
    of the code has to check both to see they are the same. ?: eliminates
    the redundancy and all that wasteful work.

    uri
     
    Uri Guttman, Mar 27, 2012
    #5
  6. James

    Uri Guttman Guest

    >>>>> "J" == James <> writes:

    J> Expect the same output, but differ. Why?
    J> use Data::Dumper;

    J> undef %o, %e;

    others have answered the ?: issue. i want to address that line of
    code. it is wrong in several ways.

    first off it isn't even needed before the first loop. secondly it
    doesn't do what you think it does. the proper way to clear hashes is to
    assign an empty list to them:

    %o = () ;

    undef is not meant to be used on aggregates (arrays and hashes). it not
    only clears the data, it reclaims all storage inside it. and it leads to
    a worse problem which is using defined on aggregates to see if they have
    any elements. and that is very wrong as defined on a hash which has been
    undef'ed will be false but if is ever had elements but was empty now,
    defined on it will be true. and that is almost never what you expect. so
    the rule is don't use undef on aggregates and never use defined on them.

    uri
     
    Uri Guttman, Mar 27, 2012
    #6
  7. James

    Uri Guttman Guest

    >>>>> "J" == James <> writes:

    J> Thanks. So parenthesizing individual expressions is the key.
    J> ($f%2) ? ($o{$f}= -1) : ($e{$f}=1) ;

    NO! using ?: the correct way is the key. it is for returning one
    expression from the pair. it is NOT for side effects like assignment or
    calling functions. if you need that, use if/else. the first version of
    the code you had is correct. the second is incorrect and should not be
    fixed with parens. that compounds the problem.

    uri
     
    Uri Guttman, Mar 27, 2012
    #7
  8. James

    Tim McDaniel Guest

    In article <>,
    Uri Guttman <> wrote:
    >>>>>> "J" == James <> writes:

    >
    > J> Thanks. So parenthesizing individual expressions is the key.
    > J> ($f%2) ? ($o{$f}= -1) : ($e{$f}=1) ;
    >
    >NO! using ?: the correct way is the key. it is for returning one
    >expression from the pair. it is NOT for side effects like assignment
    >or calling functions.


    It was made to work, though with some difficulty, so it is a large
    terminological inexactitude to call it flatly "incorrect" and to yell
    "NO!"

    But it is pointless at best. The only plausible use of ?: really is
    for evaluating the results of expressions *for use in a larger
    expression*. If the results of the right-hand sides are not needed,
    as in this particular example, ?: gains nothing over a plain
    if-then-else. For example, it's like calling two subs with

    2*a() - b()/17;

    What's the point of the useless arithmetic? That example would be
    clearer as just

    a(); b();

    Further, the original poster hit a pitfall, a point of fragility, due
    to precedence -- and much worse, it was a silent bug.

    Moreover, others and I generally think it's worse style the more
    complicated and side-effecty a ?" expression gets.

    So while it cannot be called "incorrect", I think most people would
    strongly recommend against the above example.

    --
    Tim McDaniel,
     
    Tim McDaniel, Mar 28, 2012
    #8
  9. James

    Tim McDaniel Guest

    In article <>,
    Uri Guttman <> wrote:
    >>>>>> "J" == James <> writes:

    >
    > J> undef %o, %e;
    >
    >first off it isn't even needed before the first loop.


    Sometimes I like to have an explicit initialization, as documention
    that I have considered the issue and believe that the assignment is
    needed at that point. It's also nice if I have to move the block of
    code someone else. But I'm idiosyncratic in that respect -- I suspect
    few people do that.

    >secondly it doesn't do what you think it does.


    If nothing else, for one reason not mentioned yet. The undef docs say

    undef EXPR
    undef

    ... Note that this is a unary operator, not a list operator.

    That is, it takes either zero or one argument. It certainly doesn't
    take two or more. So the quoted line is equivalent to

    (undef(%o)), %e;

    It undefs only %o and doesn't touch %e. %e is evaluated in a void
    context, and if it returns a value, it's thrown away.

    The output under Perl 5.14 of

    #! /usr/bin/perl -w
    use strict;
    use warnings;
    my %x;
    my %y = ('sparkly' => "You might think this is deleted by undef");
    undef %x, %y;
    print "$y{'sparkly'}. If so, you'd be wrong.\n";
    exit 0;

    is

    $ perl local/test/095.pl
    Useless use of private hash in void context at local/test/095.pl line 6.
    You might think this is deleted by undef. If so, you'd be wrong.

    Note well: if the original poster had used
    use strict;
    use warnings;
    as ought to be done, the bug would have been found.

    Similarly for "my" taking only one argument (though it can be a list
    of variables), and that "use strict; use warnings;" is great.
    $ perl -e 'use warnings; my $x = 3, $y = 4;'
    Name "main::y" used only once: possible typo at -e line 1.
    That is, the warning about $main::y indicates that $y was NOT my-ed.
    $ perl -e 'use strict; use warnings; my $x = 3, $y = 4;'
    Global symbol "$y" requires explicit package name at -e line 1.
    Execution of -e aborted due to compilation errors.
    is better, having a fatal error due to the undeclared $y.
    The usual way for multiple initializations in my is with separate
    statements
    $ perl -e 'use strict; use warnings; my $x = 3; my $y = 4; print "$x $y\n"'
    3 4
    or with lists
    $ perl -e 'use strict; use warnings; my ($x, $y) = (3, 4); print "$x $y\n"'
    3 4

    >the proper way to clear hashes is to assign an empty list to them:
    >
    > %o = () ;
    >
    >undef is not meant to be used on aggregates (arrays and hashes). it
    >not only clears the data, it reclaims all storage inside it.


    Um, if (by Grice's heuristics) you're trying to imply that %o=() does
    NOT reclaim all storage, you just made undef sound better. In Perl
    5.14, the scalar value of the hash is the same for deleting every
    existing element, assigning (), or undeffing:

    #! /usr/bin/perl -w
    my %x;
    @x{0..1000} = ();
    print '%x is ', scalar(%x), "\n";
    delete @x{0..1000};
    print '%x is ', scalar(%x), "\n";
    @x{0..1000} = ();
    %x = ();
    print '%x is ', scalar(%x), "\n";
    @x{0..1000} = ();
    undef %x;
    print '%x is ', scalar(%x), "\n";
    exit 0;

    results in

    $ perl local/test/097.pl
    %x is 630/1024
    %x is 0
    %x is 0
    %x is 0

    There may well be a way to look at internals to know how much storage
    space is used for each behind the scenes, but I don't know what such a
    method might be.

    (As a tangent: I think there was a way in Perl 4 to assign to a
    subscript of an array, shrink the array to be smaller than the
    subscript, regrow past that subscript, and see the assigned value
    again. Does anyone remember the details? Please tell me that it no
    longer works.)

    >and it leads to a worse problem which is using defined on aggregates
    >to see if they have any elements.


    That is to say, using "undef %x" might lead you to think that
    "defined %x" is also usable, but "defined" on a hash table is a trap
    and a snare, because

    >and that is very wrong as defined on a hash which has been undef'ed
    >will be false but if is ever had elements but was empty now, defined
    >on it will be true. and that is almost never what you expect.


    Indeed. To illustrate that,

    #! /usr/bin/perl -w
    use strict;
    use warnings;

    my %x;
    sub checkx($) {
    print "After $_[0]\n";
    print " defined? ", (defined %x ? "yes\n" : "no\n");
    print " boolean? ", (%x ? "true\n" : "false\n");
    print "\n";
    }
    checkx("start");
    %x = ();
    checkx("empty list");
    # Quotes aren't needed around 'fred' or 'sparkly',
    # but I'd rather not go into the bareword rules.
    $x{'fred'} = 'barney';
    $x{23} = 45;
    delete $x{23};
    delete $x{'fred'};
    checkx("deleting last element");
    %x = ();
    checkx("again empty list");
    undef %x;
    checkx("undeffing");

    exit 0;

    results in

    $ perl local/test/094.pl
    defined(%hash) is deprecated at local/test/094.pl line 8.
    (Maybe you should just omit the defined()?)
    After start
    defined? no
    boolean? false

    After empty list
    defined? no
    boolean? false

    After deleting last element
    defined? yes
    boolean? false

    After again empty list
    defined? yes
    boolean? false

    After undeffing
    defined? no
    boolean? false

    That is, "use warnings;" again comes through. And the program shows
    that a simple use of %x in boolean context like
    if (! %x)
    tells you accurately in each case that %x has no elements, but
    if (! defined %x)
    is not a reliable indication of that.

    --
    Tim McDaniel,
     
    Tim McDaniel, Mar 28, 2012
    #9
  10. James

    Tim McDaniel Guest

    Getting old values back

    In article <jku4qp$h9a$>,
    Tim McDaniel <> wrote:
    >(As a tangent: I think there was a way in Perl 4 to assign to a
    >subscript of an array, shrink the array to be smaller than the
    >subscript, regrow past that subscript, and see the assigned value
    >again. Does anyone remember the details? Please tell me that it no
    >longer works.)


    Found it in "man perldata":

    The length of an array is a scalar value. You may find the length
    of array @days by evaluating $#days, as in csh. However, this
    isn't the length of the array; it's the subscript of the last
    element, which is a different value since there is ordinarily a
    0th element. Assigning to $#days actually changes the length of
    the array. Shortening an array this way destroys intervening
    values. Lengthening an array that was previously shortened does
    not recover values that were in those elements. (It used to do so
    in Perl 4, but we had to break this to make sure destructors were
    called when expected.)

    --
    Tim McDaniel,
     
    Tim McDaniel, Mar 28, 2012
    #10
  11. (Tim McDaniel) writes:
    > In article <>,
    > Uri Guttman <> wrote:
    >>>>>>> "J" == James <> writes:

    >>
    >> J> Thanks. So parenthesizing individual expressions is the key.
    >> J> ($f%2) ? ($o{$f}= -1) : ($e{$f}=1) ;
    >>
    >>NO! using ?: the correct way is the key. it is for returning one
    >>expression from the pair. it is NOT for side effects like assignment
    >>or calling functions.

    >
    > It was made to work, though with some difficulty, so it is a large
    > terminological inexactitude to call it flatly "incorrect" and to yell
    > "NO!"


    Below is a quote from the perlop(1) manpage:

    The operator may be assigned to if both the 2nd and 3rd
    arguments are legal lvalues (meaning that you can assign to
    them):

    ($a_or_b ? $a : $b) = $c;

    Because this operator produces an assignable result, using
    assignments without parentheses will get you in trouble. For
    example, this:

    $a % 2 ? $a += 10 : $a += 2

    Really means this:

    (($a % 2) ? ($a += 10) : $a) += 2

    Rather than this:

    ($a % 2) ? ($a += 10) : ($a += 2)

    That should probably be written more simply as:

    $a += ($a % 2) ? 10 : 2;

    I would usually avoid the second form because it discards the result
    of the ?: and needlessly repeats the variable and the operator in both
    terms. OTOH, results are frequently discarded, so that's not a 'hard'
    reason. I have certainly used the first form whenever it was
    convenient[*]. That ?: returns an lvalue in Perl is different from the
    C ?: which implies some conscious design descision.

    [*] I actually used to do

    (a ? func_a : func_b)(a, b, c);

    in C or

    ($a ? \&func_a : \&func_b)->($a, $b, $c)

    in Perl until I sadly realized that no compiler will ever 'optimize
    that' in the seemingly obvious way: After all, it's not a common
    coding blunder mathematically oriented perpetual newbies with a
    desired to avoid learning are wont to make ...
     
    Rainer Weikusat, Mar 28, 2012
    #11
  12. James

    Tim McDaniel Guest

    Ben, thank you for your clear and cogent reply (as usual). I quite
    agree with you that restricting scope of a variable by

    > {
    > my (%o, %e);
    > ...;
    > }


    is often a good technique, and that @a=() may be more time-efficient
    than undef @a if you want to add elements again to @a "(and if you
    aren't, why is it still in scope?)".

    --
    Tim McDaniel,
     
    Tim McDaniel, Mar 28, 2012
    #12
  13. James

    Tim McDaniel Guest

    In article <4f72fa2c$3$fuzhry+tra$>,
    Shmuel (Seymour J.) Metz <> wrote:
    >In <jku13u$r0o$>, on 03/28/2012
    > at 03:38 AM, (Tim McDaniel) said:
    >
    >>But it is pointless at best. The only plausible use of ?: really is
    >>for evaluating the results of expressions *for use in a larger
    >>expression*.

    >
    >Whats wrong with using ?: in an expression that is not part of a
    >larger expression, e.g.,
    >
    >my $lhs = $foo ? $bar : $baz;


    Since "=" is an operator (and += -= and all the rest), I count that as
    being part of a larger expression.

    In any event, I meant "the only really plausible use of ?: is where
    the value is used, which means outside of void context" regardless of
    whether there's an operator that expressly shows it explicitly.
    For example,

    foreach ($use_primary ? @primary : @secondary)

    looks OK to me.

    --
    Tim McDaniel,
     
    Tim McDaniel, Mar 29, 2012
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,250
    Smokey Grindel
    Dec 2, 2006
  2. Tao Wang
    Replies:
    4
    Views:
    339
    Tao Wang
    Nov 9, 2005
  3. Christopher Brewster
    Replies:
    5
    Views:
    371
    John Machin
    Nov 14, 2008
  4. Michael Tan
    Replies:
    32
    Views:
    1,079
    Ara.T.Howard
    Jul 21, 2005
  5. denmat
    Replies:
    2
    Views:
    194
    denmat
    Apr 23, 2008
Loading...

Share This Page