This and other RFCs are available on the web at
  http://dev.perl.org/rfc/

=head1 TITLE

Optional 2nd argument to C<pop()> and C<shift()>

=head1 VERSION

  Maintainer: Jonathan Scott Duff <[EMAIL PROTECTED]>
  Date: 7 Aug 2000
  Last-Modified: 1 Sep 2000
  Version: 3
  Mailing List: [EMAIL PROTECTED]
  Number: 56
  Status: Developing

=head1 ABSTRACT

The inverse operations to C<pop()> and C<shift()> both accept a LIST to
"add" to an array, yet C<pop()> and C<shift()> only remove B<one> element
from an array.  In the interest of symmetry and TMTOWTDI, C<pop()> and
C<shift> should allow the programmer to remove multiple items from an
array.

=head1 DESCRIPTION

The intent should be obvious, but I'll point it out anyway.

=head2 pop

The documentation for Perl 5.6.0 states that pop has one of two forms:
C<pop ARRAY>, or just C<pop>.  This RFC proposes that a third form be
added to C<pop()>

=over 4

=item pop ARRAY, EXPR

EXPR would be evaluated to determine the number of elements to remove
from the end of ARRAY and that number would be removed and returned.
Thus C<pop()> would be a more natural inverse to C<push()> (If you can
add multiple elements to an array with C<push()>, why can't you remove
multiple elements from an array with C<pop>?)

=back

This functionality can currently be accomplished with C<splice()>, but
it is non-obvious that C<splice()> should be the routine to call and
the method isn't at all intuitive.  To "pop" the last $N items off of
the end of an array using C<splice()>, the call looks like this:

        splice @array, -$N;             # remove the last $N items

contrast to the more natural looking

        pop @array, $N;                 # remove the last $N items

Aaron J Mackey <[EMAIL PROTECTED]> asked whether or not this should
really be equivalent to:

        reverse splice @b, -$N;         # As if we'd popped each individually

I think that the following should hold:

        @a = pop @b, $n;
        push @b, @a;                    # @b now in its original state.
        
Thus, the 2 argument version of C<pop()> should treat the C<$N>
elements as a group.

=head2 shift

The semantics for C<shift()> are similar to C<pop()> except that it
operates on the other end of the array.  C<shift()> also suffers from
the inability to shift more than one element from the array.  Just
like C<pop()>, the two forms of C<shift()> are a C<shift ARRAY>, and
just plain C<shift>.  This RFC proposes that a third form be added:

=over 4

=item shift ARRAY, EXPR

EXPR would be evaluated to determine the number of elements to remove
from the beginning of ARRAY and that number would be removed and returned.
Thus, C<shift()> would be a more natural inverse to C<unshift>.  (If
you can add multiple elements to an array with C<unshift()>, why can't
you remove multiple elements with C<shift()>?)

=back

As with C<pop()> the proposed semantics can be accomplished with
C<splice()> and are just as un-intuitive:

        splice @array, 0, $N;           # remove the first $N elements

contrast to

        shift @array, $N;               # remove the first $N elements

Again, as with C<pop()>, C<shift()> should treat the first $N elements
of the C<@array> as a group so that the following holds:

        @a = shift @b, $N;              # remove the first $N elements
        unshift @b, @a;                 # put them back
                                        # @b is unchanged

=head2 Random examples

        @numbers = 1..10;
        $ten = pop @numbers;            # still works
        @popped = pop @numbers, 3;      # Take away 7, 8, 9
        push @numbers, @popped;         # Put 'em back
        @popped = pop @numbers, 0;      # Nothing happens
        @popped = pop @numbers, 9;      # And then there were none.

        @numbers = 1..10;
        @popped = pop @numbers, 100;    # And then there were none but
                                        # @popped only has 10 things

        @numbers = 1..10;
        $one = shift @numbers;          # still works
        @shifted = shift @numbers, 3;   # Take away 2, 3, and 4
        unshift @numbers, @shifted;     # Put 'em back
        @shifted = shift @numbers, 0;   # Nothing happens
        @shifted = shift @numbers, 9;   # And then there were none.

        @numbers = 1..10;
        @shifted = shift @numbers, 100; # And then there were none but
                                        # @shifted only has 10 things

=head1 IMPLEMENTATION

I don't know the gory details other than it should be possible.
However, there is one implementation detail that occurs to me:
What should happen when the expression given to C<pop()>, or
C<shift()> evaluates to a negative number?  I see three options:

        1) Nothing.  We can only pop/shift positive amounts
        2) Act as if the number were positive  (i.e. pop @array, abs(EXPR))
        3) C<pop()> would then act as C<shift()> and C<shift()> would
           act as C<pop()>

I propose that option #3 be adopted since it seems the most Perlian
and so far no one has disagreed.  :-)

=head1 MIGRATION

Gisle Aas <[EMAIL PROTECTED]> mentioned that the behavior of code
such as this:

        foo(pop @a, "bar");

would be changed by this proposal and that the perl5 to perl6
converter would need to handle this case.  Similar provisions would
need to be made for the proposed 2-argument C<shift()>

=head1 ISSUES

Several people have commented on the proposed return values for the
new forms of C<shift> and C<pop>.  The author of this RFC continues to
maintain that the following identities should hold:

        push(@array, pop(@array, $N));          # @array is unchanged
        unshift(@array, shift(@array, $N));     # @array is unchanged

=head1 REFERENCES

The Perl 5.6.0 documentation
L<perlfunc/pop>
L<perlfunc/shift>
L<perlfunc/splice>

Comments on return values
http://www.mail-archive.com/perl6-language@perl.org/msg01306.html
http://www.mail-archive.com/perl6-language@perl.org/msg02465.html

Perl5 -> Perl6 translation issues
http://www.mail-archive.com/perl6-language@perl.org/msg01328.html

Reply via email to