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

I hadn't realized this, but unary minus has an interesting behaviour in some cases.

What do you think this code prints if you type in -1 and hit enter?

perl -ne'chomp; $x=$_; print "x=$x, -x=",-$x,"\n";'
I was expecting

x=-1, -x=1

which seemed like a reasonable guess.

What I got was

x=-1, -x=+1

The unexpected "+" sign goes away if $x isn't a string, or if you force a numeric context by printing "0-$x" rather than just -$x.

The behaviour is documented in perlop, where it says:

Unary "-" performs arithmetic negation if the operand is numeric. If the operand is an identifier, a string consisting of a minus sign concatenated with the identifier is returned. Otherwise, if the string starts with a plus or minus, a string starting with the opposite sign is returned. One effect of these rules is that "-bareword" is equivalent to "-bareword".

I guess my question is "But why???". This doesn't seem to serve any useful purpose, does it? For instance, if you change the script to read

perl -ne'chomp; $x=0+$_; print "x=$x, -x=",-$x,"\n";'
then the oddity disappears, since $x is no longer a string. That doesn't seem very DWIM-ish to me...

Edit: Added bold to highlight the part of the perlop passage I'm questioning...


Mike

Replies are listed 'Best First'.
Re: Interesting unary - oddity
by ikegami (Patriarch) on Aug 27, 2004 at 17:11 UTC
    I guess my question is "But why???". This doesn't seem to serve any useful purpose, does it? For instance, if you change the script to read

    It's used mostly for unordered function parameters:

    $x = Dog->new( -size => 'small', # ok, this would be -aggresiveness => 'low', # quoted by =>, and -hair_style => 'curly', # ... -hair_lenght => 'short', ) package Dog; sub new { my %args = @_; my $size = $args{-size}; # ... these would be my $age = $args{-age}; # quoted by the {}, but ... my %hair_properties = @args{ -hair_style, # ... these would need -hair_lenght, # quoting without -hair_colour, # unary-'-'. }; ... }

      I'd write that as:

      my %hair_properties = @args{qw( hair_style hair_length hair_color )}; # ^^^^^ Blasted Brits who can't accept # a simplification of the language . . .

      That way your users won't have to type the extra '-' char. Further, this method is actually shorter when your list starts growing (four-char overhead of qw() stays constant).

      "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

        oh I agree. I've never used this type of '-'. But CGI.pm uses it that way, for example.

        ps - I'm not a brit.

Re: Interesting unary - oddity
by davido (Cardinal) on Aug 27, 2004 at 16:19 UTC

    One reason for this is to allow for hyphen-prefixed hash keys. $hash{-key} has a key called "-key", not the negative of "key".

    On the other hand, $hash{+key} is seen as an expression.


    Dave

      Hmm, that means -bareword makes sense, which I don't disagree with.

      My problem is with -"-key" being "+key". That's harder to justify, isn't it?


      Mike
        One possible explanation is that this implementation is mathematically equivalent to stripping the minus sign, but doesn't require changing the length of the string, which is somewhat faster. In C, switching the sign requires a single character write, while removing it requires making a new copy of the string that's one character shorter; even in Perl using substr, it's somewhat faster:
        Benchmark: timing 100000 iterations of switchsign, unsign... switchsign: 4 wallclock secs ( 1.37 usr + 0.00 sys = 1.37 CPU) @ 72992.70/s (n=100000) unsign: 4 wallclock secs ( 1.51 usr + 0.00 sys = 1.51 CPU) @ 66225.17/s (n=100000)
Re: Interesting unary - oddity
by elwarren (Priest) on Aug 27, 2004 at 21:37 UTC
    If you set params like -useMap and +useMap then this could be used to negate the param. I have no idea if this is why, but it's another possiblity...
      That only makes sense if unary-+ also auto-quoted barewords, but it doesn't.

      You can't trigger that behavior with barewords, so that's not a concern.

      Makeshifts last the longest.