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

I think I understand, now, why this doesn't work:

my $name = 'Myles na Gopaleen'; print (split ' ', $name)[-1];

and I know that I can get it to work like this:

print +(split ' ', $name)[-1];

or else like this:

print ((split ' ', $name)[-1]);

My question is this: where is this particular (not to say peculiar:) syntax required? For example, I can do this:

push @surnames, (split ' ', $name)[-1];

No unary plus sign, no problem. Does this mean that there are different types of list context?

I thought that it might be a special syntax construct for print. But I found more surprises in store, when I discovered that this works:

print OUT (split ' ', $name)[-1];

Furthermore, my researches turned up a few things like this:

my @year = map +(localtime $_)[5], @records;

What is it I'm missing?

TIA

dave

Replies are listed 'Best First'.
Re: Confused about unary +
by sgifford (Prior) on Aug 25, 2003 at 19:42 UTC
    perl -w explains the behavior you're seeing:
    print (...) interpreted as function at /tmp/t86 line 6.
    

    Perl is interpreting the print statement, followed by parentheses, is a call to print with the arguments in parentheses (print("hi there") instead of print "hi there").

    This is an ambiguous syntax, which is why it generates a warning.

    You can work around it, as you have, by putting something between the print and the parentheses, or by actually using a parenthesized call to print:

    print ((split ' ', $name)[-1]);

      Sorry, I must be a bit slow on the uptake, but I still don't understand.

      Perl is interpreting the print statement, followed by parentheses, as a call to print with the arguments in parentheses (print("hi there") instead of print "hi there");.

      This:

      print("hi there")

      works perfectly (with or without strictures and warnings) with my version of perl.

      Still confused

      dave

        It's not ambiguous.

        Something like:

        print (1,2)[0];
        is ambiguous---it could be
        (print(1,2))[0];
        or
        print((1,2))[0];
        Perl's not sure which you mean, so it issues a warning (if you have warnings enabled), and arbitrarily chooses the second.

        Now this is a little bit silly, since the second interpretation is a syntax error, and you can argue that Perl should be smarter about this, but it's not, so you have to be more explicit.

        Running with warnings on will help you catch errors like this more easily; if you don't understand them, sending them to splain will help:

        $ perl -we'print (1,2)[0];' 2>&1 |splain print (...) interpreted as function at -e line 1 (#1) (W syntax) You've run afoul of the rule that says that any list op +erator followed by parentheses turns into a function, with all the list operators arguments found inside the parentheses. See perlop/Terms and List Operators (Leftward). ...
Re: Confused about unary +
by fletcher_the_dog (Friar) on Aug 25, 2003 at 19:43 UTC
    In the perldoc for 'print' it says:
    be careful not to follow the print keyword with a left parenthesis unless you want the corresponding right parenthesis to terminate the arguments to the prin +t
    I would assume this would hold true for any built-in or predeclared subroutine where you are not required to use parens
      It's not only true for any build-in subroutine, it's true for any user defined subroutine as well. Why perldoc puts the remark at print, and why the warning only occurs at print and friends has been a mystery for me ever since I started programming Perl.

      Abigail

        Thanks. I suppose that my question can thus be summarised as:

        Who are print's friends?

        dave

      Yes, thanks, I had seen that :-) But if you re-read my post, you will see that I am confused about the more general usage of unary +.

        I think the point is that this use of unary + to disambiguate various forms of syntax is:

        • Unique to Perl.

          I'm reasonably sure you won't find any other language that overloads a mathematical symbol for a purely syntactic purpose this way. Unary + or any other.

        • A bit of a hack.

          The ambiguities in the Perl syntax that lead to the requirement to disambiguate them in this way simply don't arise in most other languages. Either the parens are required, or spaces are significant and therefore serve (and can be relied upon) to prevent the ambiguity from arising.

        • Has absolutely nothing to do with any mathematical or semantic properties that unary plus has.

          Essentially, any token could have been used to serve this purpose. Unary + just happened to be convenient.

          My best guess as to why unary + was chosen to fullfil this extra-semantic role is that, in most places where you can legitimately use unary +, in its mathematical and/or semantic role, it has exactly zero effect.

          Eg. $x=-1; print + -1; # print '-1'.

          We could always write positive numbers starting with +, for( my $i=+0; $i< +100; $i += +1){ .. };. We don't because, in most if not all cases, it has exactly zero effect.

          However, it does have an effect at the level of the parser. When the parser encounters a +, especially one that was not preceeded by an expression or term, then the parser know what follows must be an expression or term and not a list.

          So, my guess is that seeing as the parser has to deal with this mathematically valid, but otherwise semantically useless syntax -- any expression or term can legally preceeded by unary + -- then using it to disambigute those situations where an expression might be mistaken for a list added little or no overhead to the parser, but saved inventing a token for this purpose--which perl suffers from a distinct glut of anyway:)--and also allowed Perl's "whitespace is insignificant", free-form syntax to remain without requiring a special case that might otherwise have been required.

        Reading that back, I'm not at all sure that this explanation is any clearer than those that preceed it, or even that it is completely correct, but it made sense as I typed it:)

        Just to add another one to your list

        @_ = 'world!'; my %hash; $hash{ shift } = 'Hello'; $hash{ +shift } = 'Goodbye'; print "$k => $v\n" while my($k, $v) = each %hash; # prints shift => 'Hello' world! => 'Goodbye'

        In this case using shift() instead of +shift would have served to force the compiler to treat shift as an term (and therefore a function as there is no sigil) rather than as a (splendid) bareword string as in the first line above.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
        If I understand your problem, I can solve it! Of course, the same can be said for you.

Re: Confused about unary +
by rir (Vicar) on Aug 25, 2003 at 19:26 UTC
    Are you overlooking the "if it looks like a function call parse it as one" rule for parentheses?

    Builtin functions don't necessarily take lists like user defined functions. Look up the apropriate builtins and check the docs regarding prototypes.

Re: Confused about unary +
by diotalevi (Canon) on Aug 25, 2003 at 20:42 UTC

    Its also useful for distinguishing between { } as a block and as an anonymous hash reference.

    map { ... } LIST # Executes the block, once per iteration map +{ ... }, LIST # Returns a bunch of hash references