Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

passing an array without a name to pop()

by TieUpYourCamel (Scribe)
on Dec 03, 2019 at 19:09 UTC ( [id://11109616]=perlquestion: print w/replies, xml ) Need Help??

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

I'm off on a tangent of a tangent, not really solving a real problem, but I've come across this oddity and it's really bugging me. In each online example or tutorial for pop() they always use a named array. Is it possible to not do that? Instead of this:
my @odds = (1,3,5,7,9); print pop(@odds);
Is there a way to combine that onto one line? I've tried several variations, all of them generate an error, shown in the comments below the code:
use strict; use warnings; use v5.30; #works my @odds = (1,3,5,7,9); print pop(@odds); #9 (no error) print pop((2,4,6)); # Experimental pop on scalar is now forbidden ... near "))" print pop(@(2,4,6)); # Number found where operator expected ... near "@(2" # (Missing operator before 2?) # syntax error ... near "@(2" print pop(@{2,4,6}); # Useless use of a constant (2) in void context ... line 19. # Useless use of a constant (4) in void context ... line 19. # Can't use string ("6") as an ARRAY ref while "strict refs" in use .. +. line 19.
What's particularly curious is I know I've used the @{} construct before to explicitly define an array, using XML::Simple.
$ErrorResponse = $xml->XMLin($objResponse->content, ForceArray => 1); @Errors = @{$ErrorResponse->{Errors}};
I must be missing something, particularly in that first example: print pop((2,4,6)); generates the error "Experimental pop on scalar is now forbidden". However, (2,4,6) clearly isn't a scalar.

Replies are listed 'Best First'.
Re: passing an array without a name to pop()
by Paladin (Vicar) on Dec 03, 2019 at 19:16 UTC
    Your last one was close. print pop @{ [2,4,6] };
Re: passing an array without a name to pop()
by haukex (Archbishop) on Dec 03, 2019 at 20:59 UTC
    However, (2,4,6) clearly isn't a scalar.

    No, and it isn't an array either - it's a list. Note that lists like the one you showed behave differently in scalar contexts than arrays do (which return the number of elements), see the Comma Operator:

    In scalar context it evaluates its left argument, throws that value away, then evaluates its right argument and returns that value. ... In list context, it's just the list argument separator, and inserts both its arguments into the list.

    The @{...} is a dereference operator, so you need to give it a reference for it to operate on, such as [2,4,6] as Paladin showed. See perlreftut and perlref.

Re: passing an array without a name to pop()
by ikegami (Patriarch) on Dec 03, 2019 at 21:36 UTC

    The syntax for pop is

    pop ARRAY pop
    which means
    pop @NAME pop @BLOCK pop EXPR->@* pop

    The block and the expression are expected to evaluate to a reference to an array. [ ... ] creates an array and a reference to it, and evaluates to a reference. This means you can use:

    pop @{ [ 2, 4, 6 ] }

    or

    pop [ 2, 4, 6 ]->@*

    Note that EXPR->@* requires Perl 5.24+. It's also available in Perl 5.20+ by adding both use feature qw( postderef ); and no warnings qw( experimental::postderef );, or by adding use experimental qw( postderef );.

Re: passing an array without a name to pop()
by ikegami (Patriarch) on Dec 03, 2019 at 21:44 UTC

    However, (2,4,6) clearly isn't a scalar.

    Actually, it is.

    Well, it's a Perl expression. But it's a scalar in the same sense that 3+5 is a scalar because it evaluates to scalar.

    In scalar context, (2,4,6) evaluates to the single scalar 6. That is the case here.

    In list context, (2,4,6) evaluates to the three scalars 2, 4 and 6. That is not the case here.

    The block is expected to return a single scalar that is a reference, so it's evaluated in scalar context, so the last statement of the block is evaluated in scalar context.

Re: passing an array without a name to pop()
by BillKSmith (Monsignor) on Dec 03, 2019 at 21:27 UTC
    Refer the FAQ "What is the difference between a list and an array?" in perlfaq4. You are specifying a 'LIST', not an 'anonymous ARRAY'. The syntax in documentation pop shows that if pop takes an argument, it must be an 'ARRAY'. Contrast with sort which does accept a 'LIST'.
    Bill
Re: passing an array without a name to pop()
by johngg (Canon) on Dec 03, 2019 at 22:44 UTC

    Another way is to take advantage of pop's default behaviour of acting on @_ by calling an anonymous subroutine on the fly.

    johngg@shiraz:~/perl/Monks$ perl -Mstrict -Mwarnings -E ' say sub { pop }->( 1, 3, 5, 7, 9 );' 9

    I hope this is of interest.

    Update: Note that shift can work the same way and that both by default operate on @ARGV in the main program.

    johngg@shiraz:~/perl/Monks$ perl -Mstrict -Mwarnings -E ' say sub { shift }->( 1, 3, 5, 7, 9 );' 1 johngg@shiraz:~/perl/Monks$ perl -Mstrict -Mwarnings -E 'say pop' a b +c c johngg@shiraz:~/perl/Monks$ perl -Mstrict -Mwarnings -E 'say shift' a +b c a

    Cheers,

    JohnGG

Re: passing an array without a name to pop()
by The_Dj (Beadle) on Dec 04, 2019 at 06:45 UTC
    Having a look at the forest with all those trees in the way...

    Functionally, pop does 2 things:
       1] removes the last element from an array and
       2] returns that last element (for you to do things with)

    Passing a literal array rather than a named variable means that the balance of the array is lost to the great bit-bucket in the sky immediately.
    That means that the effect 1] above is lost.
    That means that all you are really doing is 2] - getting the last entry in a list.

    and that is very easily:
    $x=[1,3,5,7,9]->[-1]
    or
    print [1,3,5,7,9]->[-1]
    (Well, hard-coded like this, you may as well just grab the '9' and be done, but let's pretend this is auto-generated in an eval or something.)

    HTH
Re: passing an array without a name to pop()
by Fletch (Bishop) on Dec 03, 2019 at 19:15 UTC

    Your list of numbers is a list; the problem is that pop is the source of the surrounding context and provides a scalar one. If you check the prototype, pop is ";+" and + is a bit weird. Thus quoth perlsub:

    The "+" prototype is a special alternative to "$" that will act li +ke "\[@%]" when given a literal array or hash variable, but will othe +rwise force scalar context on the argument. This is useful for functions + which should accept either a literal array or an array reference as the argument:

    Update: Tweaked formatting.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      If you check the prototype, pop is ";+"

      No, not anymore, this was an experiment added in Perl 5.14 and removed in 5.24; see "Array and hash container functions accept references" (aka "autoderef") in perlexperiment. Its prototype has gone back to ;\@, like it was in 5.12 and below. The removal of the feature is why the "Experimental pop on scalar is now forbidden" error happens in the first place.

        Derp! That's what I get for trying it on my older desktop install instead of a close-to-current version.

        The cake is a lie.
        The cake is a lie.
        The cake is a lie.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (6)
As of 2024-03-28 23:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found