あおきです。
1999 年最後のメールになるか…

  In mail [ruby-dev:8767]
    Re: [REQ] Array#each{|a,b,...|}, Array#shift/pop(num)
    Kazunori NISHI <kazunori / swlab.csce.kyushu-u.ac.jp> wrote:

> 西@九大です。
> 
> From: matz / netlab.co.jp (Yukihiro Matsumoto)
> > 本当に欲しいものは shift/pop ではなく、
> ...
> > なる定義の「破壊的な抽出」メソッドではないですか?

> > 名前はなんだろう?
> 
> perl::splice は使った事ないのですが(何をやるものかわからなかったらしい)、
> 荒井さんのコードを見る限り、まさに Array#splice がピッタリな気がします。

ぼくは splice をそのまま導入することには賛成できません。
理由は以下の4点です。

1  後に値を代入するのは、array[args]=val または fill でできる
2  いま必要とされているのは splice のうち破壊的抽出の機能で
   それ以外の機能(あとに値を代入)を導入する理由はない
3  delete_at(長さ1の破壊的抽出) と array[index]=val(長さ1の代入)は
   別のメソッドとして用意されているのだから、長さを持つ抽出と
   代入も別のメソッドとしてあるほうがよい
4  要素をセットすると同時にその部分の要素を取りだすメソッドは
   他にはない

そのかわりに、破壊的抽出のみを行う Array#exclude を提案します。
以下、array は [0,1,2,3,4] として

part = array.exclude( 2, 2 )
# part  : [2,3]
# array : [0,1,4]

part = array.exclude( 0..1 )
# part  : [0,1]
# array : [2,3,4]

となるような動作を想定しています。
Ruby で適当にシミュレートするとこんな感じ。

class Array 
  def exclude( *args )
    ret = self[ *args ]
    self[ *args ] = []
    ret
  end
end

名前は exclude でなくてもいいですが、
こういう働きをするメソッドはぜひ欲しいです。

--
ちなみに pop(3) にも反対です。
pop は「最後部の要素をとりのぞく」という目的を持つメソッドであって、
pop(3) というのは「3回最後部の要素をとりのぞく」と解釈するほかありません。
しかし、Ruby のライブラリにはイテレータを使わずに「x 回 〜 する」という
意味をもつメソッドは存在せず、pop(3) の働きは非常に想起しにくいからです。
-------------------------------------------------------------------
あおきみねろう

ちゃんと C で書いたぞ版(void_array がいまいちな感じ)
--- org.array.c	Fri Dec 17 23:40:38 1999
+++ array.c	Fri Dec 31 20:23:53 1999
@@ -575,6 +575,51 @@
     return arg2;
 }
 
+static VALUE void_array;
+
+static VALUE
+rb_ary_exclude(argc, argv, ary)
+    int argc;
+    VALUE *argv;
+    VALUE ary;
+{
+    VALUE arg1, arg2;
+    VALUE ary2;
+    long beg = 0, len = 0;
+
+    if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) {
+	beg = NUM2LONG(arg1);
+	len = NUM2LONG(arg2);
+    }
+    else if (rb_range_beg_len(arg1, &beg, &len, RARRAY(ary)->len, 1)) {
+	/* check if idx is Range */
+    }
+    else {
+        rb_raise(rb_eTypeError, "wrong argument type");
+    }
+
+    /* copy from rb_ary_subary() & rb_ary_replace() */
+    if (beg > RARRAY(ary)->len) return Qnil;
+    if (beg < 0) {
+	beg = RARRAY(ary)->len + beg;
+    }
+    if (beg < 0) {
+	beg -= RARRAY(ary)->len;
+	rb_raise(rb_eIndexError, "index %d out of array", beg);
+    }
+    if (len < 0) rb_raise(rb_eIndexError, "negative length %d", len);
+    if (beg + len > RARRAY(ary)->len) {
+	len = RARRAY(ary)->len - beg;
+    }
+    if (len == 0) return rb_ary_new2(0);
+    ary2 = rb_ary_new2(len);
+    MEMCPY(RARRAY(ary2)->ptr, RARRAY(ary)->ptr+beg, VALUE, len);
+    RARRAY(ary2)->len = len;
+    rb_ary_replace(ary, beg, len, void_array);
+
+    return ary2;
+}
+
 VALUE
 rb_ary_each(ary)
     VALUE ary;
@@ -1470,6 +1515,8 @@
 void
 Init_Array()
 {
+    volatile VALUE tmp;
+
     rb_cArray  = rb_define_class("Array", rb_cObject);
     rb_include_module(rb_cArray, rb_mEnumerable);
 
@@ -1521,6 +1568,7 @@
     rb_define_method(rb_cArray, "delete_at", rb_ary_delete_at, 1);
     rb_define_method(rb_cArray, "delete_if", rb_ary_delete_if, 0);
     rb_define_method(rb_cArray, "reject!", rb_ary_delete_if, 0);
+    rb_define_method(rb_cArray, "exclude", rb_ary_exclude, -1);
     rb_define_method(rb_cArray, "filter", rb_ary_filter, 0);
     rb_define_method(rb_cArray, "replace", rb_ary_replace_method, 1);
     rb_define_method(rb_cArray, "clear", rb_ary_clear, 0);
@@ -1547,4 +1595,6 @@
     rb_define_method(rb_cArray, "nitems", rb_ary_nitems, 0);
 
     cmp = rb_intern("<=>");
+    void_array = tmp = rb_ary_new();
+    rb_global_variable(&void_array);
 }