13

Does anyone know what parsing or precedence decisions resulted in the warning 'Use of "shift" without parentheses is ambiguous' being issued for code like:

shift . 'some string';

# and not

(shift) . 'some string'; # or
shift() . 'some string';

Is this intentional to make certain syntactic constructs easier? Or is it merely an artifact of the way perl's parser works?

Note: this is a discussion about language design, not a place to suggest

"@{[shift]}some string"
brian d foy
  • 129,424
  • 31
  • 207
  • 592
Eric Strom
  • 39,821
  • 2
  • 80
  • 152

2 Answers2

30

With use diagnostics, you get the helpful message:

    Warning: Use of "shift" without parentheses is ambiguous at (eval
        9)[/usr/lib/perl5/5.8/perl5db.pl:628] line 2 (#1)
    (S ambiguous) You wrote a unary operator followed by something that
    looks like a binary operator that could also have been interpreted as a
    term or unary operator.  For instance, if you know that the rand
    function has a default argument of 1.0, and you write

        rand + 5;

    you may THINK you wrote the same thing as

        rand() + 5;

    but in actual fact, you got

        rand(+5);

    So put in parentheses to say what you really mean.

The fear is you could write something like shift .5 and it will be parsed like shift(0.5).

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
mob
  • 117,087
  • 18
  • 149
  • 283
  • I would upvote, but "my daily vote limit is reached." I think that's a bug, because I think SO went down for a few minutes right on the time when it was supposed to reset, so I'm being penalized for having voted yesterday. – Chris Lutz Oct 18 '09 at 05:34
  • in the case of rand (;$) i can see a case for the warning, however, with shift there doesn't seem to be, since shift's prototype (;\@) would prevent a string or number from being a valid argument – Eric Strom Oct 18 '09 at 17:19
  • 1
    @Eric Strom: this error comes from the tokenizer, which isn't that smart. Unrelatedly, shift's prototype isn't really (;\@), since that would make it a list operator and it is in fact a unary operator. – ysth Oct 18 '09 at 17:57
  • you mean prototype is lying to me... the horror – Eric Strom Oct 18 '09 at 19:05
  • no wait, why would (;\@) make it a list operator, i would interpret that prototype as taking zero arguments, or one which must be an @ array – Eric Strom Oct 18 '09 at 19:07
  • @Eric Strom: it just does; anything other than ($) or (_) is a list operator. Try with different prototypes: perl -we'sub foo (;\@) {} print foo @a, 1, 2, 3' – ysth Oct 19 '09 at 04:54
  • @ysth - learn something new every day, i dont think i've ever tried prototyping a sub with the expectation of getting it to work like shift. Most of my work with prototypes has been either with (&@) type prototypes or ($) for unary operators. Anyone know if the upcoming revisions to perl5 are going to adjust this parsing 'quirk', or backport any more of the builtin magic to user space? – Eric Strom Oct 19 '09 at 19:02
  • This points to something that is bothering me: The fad of leaving out extra parentheses on functions for _clarity_. For example, there's a difference between `join ":", @foo . $bar` and `join ( ":", @foo ) . bar`. In the first, I am concatenating `@foo . $bar` and then doing the join. It's as if I did this: `join ( ":", ( @foo . $bar ) )`. However, since I'm not use to writing parentheses when using `join`, and that works 99% of the time, I probably won't catch the error. It's always that last 1% that hides in wait and bites you in the _Southern Regions_ when you least expect it. – David W. Apr 05 '13 at 15:10
8

Ambiguous doesn't mean truly ambiguous, just ambiguous as far as the parser had determined. shift . in particular is "ambiguous" because . can start a term (e.g. .123) or an operator, so it doesn't know enough to decide whether what follows is shift's operand or an operator for which shift() is the operand (and the parser isn't smart enough to know that: a) the . isn't the start of such a term or b) .123 isn't a valid operand for shift).

ysth
  • 96,171
  • 6
  • 121
  • 214