遠藤です。

Array#product は Enumerator でなく配列を返しますが、何か理由が
あってのことでしょうか。

Array#permutation や combination のように Enumerator を返した方が
自然かつ便利だと思います。これらのメソッドは brute force 的な探索に
よく使いますが、product だけ探索前に巨大な配列を確保してしまうので
いやらしいです。

仕様変更になってしまいますが、一応言ってみました。どうでしょうか。


Index: array.c
===================================================================
--- array.c	(revision 24823)
+++ array.c	(working copy)
@@ -3858,30 +3858,35 @@
  *  call-seq:
  *     ary.product(other_ary, ...)
  *
- *  Returns an array of all combinations of elements from all arrays.
- *  The length of the returned array is the product of the length
- *  of ary and the argument arrays
+ * When invoked with a block, yields all combinations of elements
+ * from all arrays.
  *
- *     [1,2,3].product([4,5])     # => [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
- *     [1,2].product([1,2])       # => [[1,1],[1,2],[2,1],[2,2]]
- *     [1,2].product([3,4],[5,6]) # => [[1,3,5],[1,3,6],[1,4,5],[1,4,6],
- *                                #     [2,3,5],[2,3,6],[2,4,5],[2,4,6]]
- *     [1,2].product()            # => [[1],[2]]
- *     [1,2].product([])          # => []
+ * When invoked without a block, returns an enumerator object instead.
+ *
+ *     [1,2,3].product([4,5]).to_a     # =>
[[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
+ *     [1,2].product([1,2]).to_a       # => [[1,1],[1,2],[2,1],[2,2]]
+ *     [1,2].product([3,4],[5,6]).to_a # => [[1,3,5],[1,3,6],[1,4,5],[1,4,6],
+ *                                     #     [2,3,5],[2,3,6],[2,4,5],[2,4,6]]
+ *     [1,2].product().to_a            # => [[1],[2]]
+ *     [1,2].product([]).to_a          # => []
  */

 static VALUE
 rb_ary_product(int argc, VALUE *argv, VALUE ary)
 {
     int n = argc+1;    /* How many arrays we're operating on */
-    volatile VALUE t0 = tmpbuf(n, sizeof(VALUE));
-    volatile VALUE t1 = tmpbuf(n, sizeof(int));
-    VALUE *arrays = (VALUE*)RSTRING_PTR(t0); /* The arrays we're
computing the product of */
-    int *counters = (int*)RSTRING_PTR(t1); /* The current position in
each one */
-    VALUE result;      /* The array we'll be returning */
+    volatile VALUE t0, t1;
+    VALUE *arrays;
+    int *counters;
     long i,j;
     long resultlen = 1;

+    RETURN_ENUMERATOR(ary, argc, argv);
+    t0 = tmpbuf(n, sizeof(VALUE));
+    t1 = tmpbuf(n, sizeof(int));
+    arrays = (VALUE*)RSTRING_PTR(t0); /* The arrays we're computing
the product of */
+    counters = (int*)RSTRING_PTR(t1); /* The current position in each one */
+
     RBASIC(t0)->klass = 0;
     RBASIC(t1)->klass = 0;

@@ -3903,7 +3908,6 @@
     }

     /* Otherwise, allocate and fill in an array of results */
-    result = rb_ary_new2(resultlen);
     for (i = 0; i < resultlen; i++) {
 	int m;
 	/* fill in one subarray */
@@ -3913,7 +3917,7 @@
 	}

 	/* put it on the result array */
-	rb_ary_push(result, subarray);
+	rb_yield(subarray);

 	/*
 	 * Increment the last counter.  If it overflows, reset to 0
@@ -3930,7 +3934,7 @@
     tmpbuf_discard(t0);
     tmpbuf_discard(t1);

-    return result;
+    return ary;
 }

 /*
Index: test/ruby/test_array.rb
===================================================================
--- test/ruby/test_array.rb	(revision 24823)
+++ test/ruby/test_array.rb	(working copy)
@@ -1306,14 +1306,14 @@

   def test_product
     assert_equal(@cls[[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]],
-                 @cls[1,2,3].product([4,5]))
-    assert_equal(@cls[[1,1],[1,2],[2,1],[2,2]], @cls[1,2].product([1,2]))
+                 @cls[1,2,3].product([4,5]).to_a)
+    assert_equal(@cls[[1,1],[1,2],[2,1],[2,2]], @cls[1,2].product([1,2]).to_a)

     assert_equal(@cls[[1,3,5],[1,3,6],[1,4,5],[1,4,6],
                    [2,3,5],[2,3,6],[2,4,5],[2,4,6]],
-                 @cls[1,2].product([3,4],[5,6]))
-    assert_equal(@cls[[1],[2]], @cls[1,2].product)
-    assert_equal(@cls[], @cls[1,2].product([]))
+                 @cls[1,2].product([3,4],[5,6]).to_a)
+    assert_equal(@cls[[1],[2]], @cls[1,2].product.to_a)
+    assert_equal(@cls[], @cls[1,2].product([]).to_a)
   end

   def test_permutation

-- 
Yusuke ENDOH <mame / tsg.ne.jp>