Skip to content
VLSI Mentor

Perl Part I · Module 5 · Arrays and Lists

push, pop, shift and unshift

Everything so far has read an array that already existed. These four functions change its length: two work at the end and two at the front, one of each pair adding and the other removing. The one you will use most is push, because it is how a script collects results while it works — walk a set of tests, push the name of each one that failed, and at the end you have both the list and the count. The detail worth knowing before you rely on them is that the two halves return different kinds of thing. The adding functions hand back the array's new length; the removing functions hand back the element they took out. Assigning the result of the wrong one gives you a number where you wanted a value, and nothing warns.

Foundation14 min readPerlPart IFundamentalsArraysIdioms

Part I · Module 5 · Chapter 5.4 · push, pop, shift and unshift

1. Four Functions, Two Ends

FunctionEndDoesReturns
pushbackaddsthe new length
popbackremovesthe element removed
unshiftfrontaddsthe new length
shiftfrontremovesthe element removed
Azvya Education Pvt. Ltd.VLSI Mentor
four-functions.pl
use strict;
use warnings;

my @q = ("b", "c");

my $after_push    = push    @q, "d";
my $after_unshift = unshift @q, "a";

printf "after push    returned %d  -> [%s]\n", $after_push,    join(" ", @q);
printf "after unshift returned %d  -> [%s]\n", $after_unshift, join(" ", @q);

my $popped  = pop   @q;
my $shifted = shift @q;

printf "pop   returned [%s] -> [%s]\n", $popped,  join(" ", @q);
printf "shift returned [%s] -> [%s]\n", $shifted, join(" ", @q);
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
after push    returned 3  -> [a b c d]
after unshift returned 4  -> [a b c d]
pop   returned [d] -> [b c]
shift returned [a] -> [b c]

Read the two printf lines for push and unshift carefully. The array printed on both is [a b c d], because both printfs ran after both modifications — but the returned values were 3 and 4, the lengths immediately after each call.

All four modify the array in place. That is the exception to Chapter 3.1 §5's rule, and the same exception the four-argument substr made in Chapter 4.5 §4.

2. The Return Values Are Not Symmetric

Azvya Education Pvt. Ltd.VLSI Mentor
return-shapes.pl
use strict;
use warnings;

my @a = ("x", "y");

my $from_push = push @a, "z";
my $from_pop  = pop  @a;

printf "push gave [%s]  <- a LENGTH\n",  $from_push;
printf "pop  gave [%s]  <- an ELEMENT\n", $from_pop;
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
push gave [3]  <- a LENGTH
pop  gave [z]  <- an ELEMENT

push returned 3. Not "z", not the array — the count of elements afterwards.

3. pop and shift on an Empty Array Are Silent

Azvya Education Pvt. Ltd.VLSI Mentor
empty-removal.pl
use strict;
use warnings;

my @empty = ();

my $popped  = pop   @empty;
my $shifted = shift @empty;

printf "pop   gave [%s]\n", (defined $popped  ? $popped  : "undef");
printf "shift gave [%s]\n", (defined $shifted ? $shifted : "undef");
printf "count still %d\n",  scalar(@empty);
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — STDOUT
pop   gave [undef]
shift gave [undef]
count still 0
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet

Both returned undef, the array stayed empty, and nothing was reported. Taking from an empty array is not an error in Perl.

That silence is what makes the common queue idiom work:

Azvya Education Pvt. Ltd.VLSI Mentor
drain-queue.pl
use strict;
use warnings;

my @work = ("alu", "fifo", "decoder");

while (my $job = shift @work) {
    print "processing $job\n";
}

print "queue empty\n";
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
processing alu
processing fifo
processing decoder
queue empty

The loop ends because shift eventually returns undef, which is false.

4. push Takes Several Values, and Flattens an Array

Azvya Education Pvt. Ltd.VLSI Mentor
push-many.pl
use strict;
use warnings;

my @a = ("x");

push @a, "y", "z";
printf "after two values : count=%d [%s]\n", scalar(@a), join(" ", @a);

my @more = ("p", "q");
push @a, @more;
printf "after push \@more : count=%d [%s]\n", scalar(@a), join(" ", @a);
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
after two values : count=3 [x y z]
after push @more : count=5 [x y z p q]

Pushing an array adds its elements, not the array as a single item. The result is five elements, flat.

That is not a special behaviour of push — it is how lists work in Perl generally, and Chapter 5.12 is the chapter devoted to it. It is convenient here and it is also why you cannot build a list of lists this way; Module 7's references are the answer to that.

And push needs no initialiser:

Azvya Education Pvt. Ltd.VLSI Mentor
no-init.pl
use strict;
use warnings;

my @failures;

push @failures, "fifo";

printf "count=%d [%s]\n", scalar(@failures), join(" ", @failures);
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
count=1 [fifo]

my @failures; is an empty array, as Chapter 5.1 §4 established, and pushing onto it works with no warning.

5. The Pattern Worth Learning: Collect As You Go

This is what the canonical index means by "how a script collects results as it goes", and it is the shape of most reporting scripts in this trade.

Azvya Education Pvt. Ltd.VLSI Mentor
collect.pl
use strict;
use warnings;

my @rows = ("alu PASS", "fifo FAIL", "decoder PASS", "regfile FAIL");

my @failures;

for my $row (@rows) {
    my ($name, $status) = split " ", $row;

    push @failures, $name if $status eq "FAIL";
}

printf "%d failure(s): %s\n", scalar(@failures), join(", ", @failures);
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
2 failure(s): fifo, regfile

Four lines of logic, and look at what the array gives you at the end:

  • The count — scalar(@failures) is the number for the report.
  • The names — join(", ", @failures) is the list for the reader.
  • The emptiness — on a clean run @failures is empty, which Chapter 5.7 turns into a one-word test.

Three pieces of a report from one accumulator. That is why push earns its Critical rating in the index.

Three borrowed constructs are credited rather than taught here: the for loop is Module 9's, my ($name, $status) = split ... is list assignment which Chapter 5.6 covers, and split " " is Chapter 4.7 §5's whitespace form — chosen deliberately over split / / for the reason that chapter measured.

Collecting rows rather than names

The same pattern with more per entry, formatted with Chapter 4.8's sprintf:

Azvya Education Pvt. Ltd.VLSI Mentor
collect-rows.pl
use strict;
use warnings;

my @rows = ("alu 184 177", "fifo 92 92", "decoder 1240 1198");

my @report;

for my $row (@rows) {
    my ($name, $total, $passed) = split " ", $row;

    push @report, sprintf("%-10s %6d %6d %6.1f%%",
        $name, $total, $passed, $passed / $total * 100);
}

print "$_\n" for @report;
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
alu           184    177   96.2%
fifo           92     92  100.0%
decoder      1240   1198   96.6%

Building the lines into an array rather than printing them immediately means you can sort them, count them, or decide not to emit them at all — the same argument Chapter 3.4 §6 made for accumulating a string with .=, now with the pieces kept separate so they remain sortable.

6. Which End, and Why It Matters

A stack uses one end: push and pop. The last thing in is the first thing out.

A queue uses both: push to add at the back, shift to take from the front. The first thing in is the first thing out.

Azvya Education Pvt. Ltd.VLSI Mentor
stack-vs-queue.pl
use strict;
use warnings;

my @stack = ();
push @stack, $_ for ("a", "b", "c");
printf "stack pops : %s %s %s\n", pop @stack, pop @stack, pop @stack;

my @queue = ();
push @queue, $_ for ("a", "b", "c");
printf "queue shifts: %s %s %s\n", shift @queue, shift @queue, shift @queue;
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
stack pops : c b a
queue shifts: a b c

For scripting work the distinction is usually about whether order matters to the reader. A list of failures should come out in the order they happened, which means push to collect and then read the array normally — not pop, which would reverse it.

unshift is the rarest of the four. Its common use is putting something at the front of a list of arguments or a list of paths to search, where "try this first" is the meaning.

7. Why This Matters in Engineering Work

Collecting failures, warnings or violations. §5's pattern, and it is everywhere. The array gives you the count and the detail from one pass.

Building report lines before deciding what to do with them. Accumulate, then sort with Chapter 5.9, then print. A script that prints as it goes cannot sort its own output.

Work queues. A list of blocks to process, with shift taking the next one. Use while (@work) rather than while (my $job = shift @work) so that a job named 0 does not end the run — §3's callout is a real bug, not a theoretical one.

And the return-value asymmetry costs real time because the failure is a number where a name should be. $added holding 3 instead of "fifo" means a later comparison against a block name never matches, which reads as a data problem. Calling these functions as statements avoids the whole class.

8. Common Mistakes

Assigning push's return value. It is the new length, not the value pushed. Call it as a statement.

Expecting pop to return the array. It returns the one element it removed.

Using while (my $x = shift @a) on data that can be false. A 0 or an empty string ends the loop early. Use while (@a) or defined(...).

Expecting pop on an empty array to complain. It returns undef, silently.

Expecting push @a, @b to nest. It flattens — Chapter 5.12.

Using pop to read a collected list. It consumes the array and reverses the order. Read it with a loop or join.

Initialising with = () because push needs it. It does not; my @a; is enough.

9. Exercise

Exercise 1 — all four, with return values. Start from a two-element array. Apply each of the four functions in turn, printing what each returned and the array afterwards. Then fill in the four-row table from §1 from your own output.

Exercise 2 — the count trap. Write my $got = push @names, "alu"; and print $got. Record the value, say what you expected, and name the chapter where you met the same shape of bug with a different function.

Exercise 3 — the empty array. Pop and shift from an empty array, printing whether each result is defined and the count afterwards. Confirm STDERR is empty.

Exercise 4 — break the queue idiom. Build a work list containing "alu", 0 and "decoder", then drain it with while (my $job = shift @work). Record which jobs were processed. Then fix it two ways — with defined and with while (@work) — and confirm all three jobs run.

Exercise 5 — collect the failures. Given six rows of name STATUS, build an array of the failing names with push, then print the count and the comma-joined list. Confirm an all-passing input gives a count of 0 and an empty list.

Exercise 6 — flatten. Push a two-element array onto a one-element array and report the final count. Say what the count would be if push nested instead, and name the chapter that covers why it does not.

Exercise 7 — stack against queue. Collect three items, then empty the array with pop three times, and again with shift three times. Report both orders and say which one you would use to report failures in the order they occurred.

10. Summary

  • push/pop work at the back; unshift/shift at the front. All four modify the array in place.
  • push and unshift return the new length; pop and shift return the element removed. Assigning the adding functions' result gives you a count — the same trap as chomp.
  • Call push and unshift as statements.
  • pop and shift on an empty array return undef silently.
  • while (my $x = shift @a) stops on a false element, not on an empty array. Prefer while (@a).
  • push accepts several values and flattens an array into the target.
  • my @a; needs no = () before pushing.
  • The collect-as-you-go pattern gives you count, detail and emptiness from one pass, which is why it is the module's most-used idiom.

Chapter 5.5 covers the one function that works in the middle of an array rather than at its ends — removing, inserting and replacing a span, with a return value that changes depending on the context it is called in.

Where this fits

Part of the Perl curriculum.