[% setvar title Optional 2nd argument to C and C %]

This file is part of the Perl 6 Archive

Note: these documents may be out of date. Do not use as reference!

To see what is currently happening visit http://www.perl6.org/

TITLE

Optional 2nd argument to pop() and shift()

VERSION

  Maintainer: Jonathan Scott Duff <duff@pobox.com>
  Date: 7 Aug 2000
  Last Modified: 1 Sep 2000
  Mailing List: perl6-language@perl.org
  Number: 56
  Version: 3
  Status: Developing

ABSTRACT

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

DESCRIPTION

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

pop

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

  • 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 pop() would be a more natural inverse to push() (If you can add multiple elements to an array with push(), why can't you remove multiple elements from an array with pop?)

This functionality can currently be accomplished with splice(), but it is non-obvious that 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 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 <ajm6q@virginia.edu> 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 pop() should treat the $N elements as a group.

shift

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

  • 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, shift() would be a more natural inverse to unshift. (If you can add multiple elements to an array with unshift(), why can't you remove multiple elements with shift()?)

As with pop() the proposed semantics can be accomplished with 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 pop(), shift() should treat the first $N elements of the @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

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

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 pop(), or 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. :-)

MIGRATION

Gisle Aas <gisle@ActiveState.com> 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 shift()

ISSUES

Several people have commented on the proposed return values for the new forms of shift and 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

REFERENCES

The Perl 5.6.0 documentation "pop" in perlfunc "shift" in perlfunc "splice" in perlfunc

Comments on return values www.mail-archive.com www.mail-archive.com

Perl5 -> Perl6 translation issues www.mail-archive.com