* Enumerable#zip Needs Love
@ 2008-01-03 22:05 James Gray
2008-01-04 6:11 ` Martin Duerst
0 siblings, 1 reply; 15+ messages in thread
From: James Gray @ 2008-01-03 22:05 UTC (permalink / raw
To: Ruby Core
The community has been building a Ruby 1.9 compatibility tip list on
my blog. While most of the changes are good, a pattern is emerging:
Enumerable#zip was damaged in the translation. The short story is:
* Making Enumerable#zip() return and Enumerable::Enumerator when
called without a block hid a very useful return value that was already
in place. Now we typically need `enum.zip(…).to_a` to get the
expected results.
* Beyond being less attractive, Enumerable::Enumerator is quite a bit
slower. It looks like `enum.zip(…).to_a` in 1.9 is about 12 times
slower than a straight `enum.zip(…)` in Ruby 1.8.
* Making Enumerable#zip() stop at the length of the shortest
Enumerable among the receiver and arguments really hurt its
usefulness. It now discards data and it's hard for us to prevent
that, since we need to lengthen all short Enumerable objects we plan
to use before the call. The Ruby 1.8 system of limiting the result
set to the size of the receiver was much more powerful, in my
opinion. We could find the longest or shortest Enumerable to get the
length we wanted, filter out the `nil` containing groups it inserted,
or trim the size of the Enumerable objects involved (easier than
expanding them).
So, I'm making a plea for restoring Enumerable#zip() to the cool
iterator we all know and love:
* Can we restore the Array return value? We can still use
`enum_for(:zip, …)` when needed. This fits in with the other
iterators that have a useful return value like all?(), any?(),
count(), drop(), inject()/reduce(), none?(), one?(), sort(), and take().
* Can we revert to the 1.8 behavior of setting the result set length
to the length of the receiver and adding `nil` objects for shorter
Enumerable arguments? That seems to give us a lot more control over
the end result.
Thanks for listening.
James Edward Gray II
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Enumerable#zip Needs Love
2008-01-03 22:05 Enumerable#zip Needs Love James Gray
@ 2008-01-04 6:11 ` Martin Duerst
2008-01-04 14:22 ` James Gray
2008-01-07 22:15 ` James Gray
0 siblings, 2 replies; 15+ messages in thread
From: Martin Duerst @ 2008-01-04 6:11 UTC (permalink / raw
To: ruby-core
Hello James,
I think the two changes have to be looked at separately.
At 07:05 08/01/04, James Gray wrote:
>The community has been building a Ruby 1.9 compatibility tip list on
>my blog. While most of the changes are good, a pattern is emerging:
>Enumerable#zip was damaged in the translation. The short story is:
>
>* Making Enumerable#zip() return and Enumerable::Enumerator when
>called without a block hid a very useful return value that was already
>in place. Now we typically need `enum.zip(...).to_a` to get the
>expected results.
My recollection may be faulty, and I may not be the typical case,
but I usually have been using zip immediately followed by some
additional operation, which should still work in 1.9, rather
than to produce an explicit array.
>* Beyond being less attractive, Enumerable::Enumerator is quite a bit
>slower. It looks like `enum.zip(...).to_a` in 1.9 is about 12 times
>slower than a straight `enum.zip(...)` in Ruby 1.8.
That looks bad. But have you looked at how much slower or
faster things get when zip is used not just to create an array?
I could also immagine that the zip.to_a combination, and some
similar combinations, could be optimized in the future.
>* Making Enumerable#zip() stop at the length of the shortest
>Enumerable among the receiver and arguments really hurt its
>usefulness. It now discards data and it's hard for us to prevent
>that, since we need to lengthen all short Enumerable objects we plan
>to use before the call. The Ruby 1.8 system of limiting the result
>set to the size of the receiver was much more powerful, in my
>opinion. We could find the longest or shortest Enumerable to get the
>length we wanted, filter out the `nil` containing groups it inserted,
>or trim the size of the Enumerable objects involved (easier than
>expanding them).
I think these arguments make a lot of sense, so I think this
should be moved back to the old behavior, unless there is some
serious implementation problem.
>So, I'm making a plea for restoring Enumerable#zip() to the cool
>iterator we all know and love:
>
>* Can we restore the Array return value? We can still use
>`enum_for(:zip, ...)` when needed. This fits in with the other
>iterators that have a useful return value like all?(), any?(),
>count(), drop(), inject()/reduce(), none?(), one?(), sort(), and take().
Many of these return a single value, where an Enumerable would really
be strange. The only ones that return an array are are drop(), take(),
and sort().
Regards, Martin.
>* Can we revert to the 1.8 behavior of setting the result set length
>to the length of the receiver and adding `nil` objects for shorter
>Enumerable arguments? That seems to give us a lot more control over
>the end result.
>
>Thanks for listening.
>
>James Edward Gray II
>
>
#-#-# Martin J. Du"rst, Assoc. Professor, Aoyama Gakuin University
#-#-# http://www.sw.it.aoyama.ac.jp mailto:duerst@it.aoyama.ac.jp
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Enumerable#zip Needs Love
2008-01-04 6:11 ` Martin Duerst
@ 2008-01-04 14:22 ` James Gray
2008-01-04 17:52 ` Rick DeNatale
2008-01-07 22:15 ` James Gray
1 sibling, 1 reply; 15+ messages in thread
From: James Gray @ 2008-01-04 14:22 UTC (permalink / raw
To: ruby-core
On Jan 4, 2008, at 12:11 AM, Martin Duerst wrote:
> I think the two changes have to be looked at separately.
Sounds good to me. I posted them here with the hope of inspiring
discussion around them. Perhaps if enough of us reach agreement, Matz
will take pity on us zip() fans. :)
> At 07:05 08/01/04, James Gray wrote:
>> The community has been building a Ruby 1.9 compatibility tip list on
>> my blog. While most of the changes are good, a pattern is emerging:
>> Enumerable#zip was damaged in the translation. The short story is:
>>
>> * Making Enumerable#zip() return and Enumerable::Enumerator when
>> called without a block hid a very useful return value that was
>> already
>> in place. Now we typically need `enum.zip(...).to_a` to get the
>> expected results.
>
> My recollection may be faulty, and I may not be the typical case,
> but I usually have been using zip immediately followed by some
> additional operation, which should still work in 1.9, rather
> than to produce an explicit array.
Well, Array is a superset of Enumerable, right? So the operations you
can follow up with are increased by an Array return value and you
don't lose access to any of the iterators.
>> * Beyond being less attractive, Enumerable::Enumerator is quite a bit
>> slower. It looks like `enum.zip(...).to_a` in 1.9 is about 12 times
>> slower than a straight `enum.zip(...)` in Ruby 1.8.
>
> That looks bad. But have you looked at how much slower or
> faster things get when zip is used not just to create an array?
I hadn't before, no. Let's check though:
$ ruby -v speed_test.rb
ruby 1.8.6 (2007-09-24 patchlevel 111) [i686-darwin9.1.0]
Rehearsal -------------------------------------------------
zip().to_a(): 8.040000 0.020000 8.060000 ( 8.066183)
zip() { }: 8.770000 0.020000 8.790000 ( 8.789457)
--------------------------------------- total: 16.850000sec
user system total real
zip().to_a(): 8.100000 0.010000 8.110000 ( 8.112016)
zip() { }: 8.820000 0.010000 8.830000 ( 8.852391)
$ ruby_dev -v speed_test.rb
ruby 1.9.0 (2007-12-25 revision 14709) [i686-darwin9.1.0]
Rehearsal -------------------------------------------------
zip().to_a(): 100.870000 9.620000 110.490000 (110.607631)
zip() { }: 82.510000 9.410000 91.920000 ( 92.208807)
-------------------------------------- total: 202.410000sec
user system total real
zip().to_a(): 99.890000 9.940000 109.830000 (109.915261)
zip() { }: 81.550000 9.470000 91.020000 ( 90.950279)
$ cat speed_test.rb
#!/usr/bin/env ruby -wKU
require "benchmark"
DATA = Array.new(25) { rand }
TESTS = 1_000_000
Benchmark.bmbm do |results|
results.report("zip().to_a():") { TESTS.times
{ DATA.zip(DATA).to_a } }
results.report("zip() { }:") { TESTS.times { DATA.zip(DATA)
{ } } }
end
__END__
Good call. It seems that zip() performance on the whole has tanked.
James Edward Gray II
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Enumerable#zip Needs Love
2008-01-04 14:22 ` James Gray
@ 2008-01-04 17:52 ` Rick DeNatale
0 siblings, 0 replies; 15+ messages in thread
From: Rick DeNatale @ 2008-01-04 17:52 UTC (permalink / raw
To: ruby-core
By the way the RDOC for Enumerable#zip for 1.9 seems to need some work:
k$ ri1.9 Enumerable#zip
--------------------------------------------------------- Enumerable#zip
enum.zip(arg, ...) => enumerator
enum.zip(arg, ...) {|arr| block } => nil
------------------------------------------------------------------------
Takes one element from _enum_ and merges corresponding elements
from each _args_. This generates a sequence of _n_-element arrays,
where _n_ is one more that the count of arguments. The length of
the sequence is truncated to the size of the shortest argument (or
_enum_). If a block given, it is invoked for each output array,
otherwise an array of arrays is returned.
a = [ 4, 5, 6 ]
b = [ 7, 8, 9 ]
[1,2,3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
[1,2].zip(a,b) #=> [[1, 4, 7], [2, 5, 8]]
a.zip([1,2],[8]) #=> [[4,1,8]]
Note that although the signature says that calling it without a block
will return an enumerator, the examples show it returning an array.
--
Rick DeNatale
My blog on Ruby
http://talklikeaduck.denhaven2.com/
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Enumerable#zip Needs Love
2008-01-04 6:11 ` Martin Duerst
2008-01-04 14:22 ` James Gray
@ 2008-01-07 22:15 ` James Gray
2008-01-08 2:07 ` Yukihiro Matsumoto
1 sibling, 1 reply; 15+ messages in thread
From: James Gray @ 2008-01-07 22:15 UTC (permalink / raw
To: ruby-core
On Jan 4, 2008, at 12:11 AM, Martin Duerst wrote:
> At 07:05 08/01/04, James Gray wrote:
>>
>
>> * Making Enumerable#zip() stop at the length of the shortest
>> Enumerable among the receiver and arguments really hurt its
>> usefulness. It now discards data and it's hard for us to prevent
>> that, since we need to lengthen all short Enumerable objects we plan
>> to use before the call. The Ruby 1.8 system of limiting the result
>> set to the size of the receiver was much more powerful, in my
>> opinion. We could find the longest or shortest Enumerable to get the
>> length we wanted, filter out the `nil` containing groups it inserted,
>> or trim the size of the Enumerable objects involved (easier than
>> expanding them).
>
> I think these arguments make a lot of sense, so I think this
> should be moved back to the old behavior, unless there is some
> serious implementation problem.
Matz, at least this much of my proposal seems uncontested. Can you
tell us the reason for the new behavior?
James Edward Gray II
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Enumerable#zip Needs Love
2008-01-07 22:15 ` James Gray
@ 2008-01-08 2:07 ` Yukihiro Matsumoto
2008-01-08 4:50 ` James Gray
0 siblings, 1 reply; 15+ messages in thread
From: Yukihiro Matsumoto @ 2008-01-08 2:07 UTC (permalink / raw
To: ruby-core
Hi,
In message "Re: Enumerable#zip Needs Love"
on Tue, 8 Jan 2008 07:15:56 +0900, James Gray <james@grayproductions.net> writes:
|Matz, at least this much of my proposal seems uncontested. Can you
|tell us the reason for the new behavior?
The rationales behind the changes were:
(a) stopping at the shortest
adopting the behavior from python where I took the idea of zip
method. I saw some use cases that the shortest stop may
helpful. Besides that it's much simpler to implement. But
there's still room for you to persuade me.
(b) return value
My estimation was that zip was mostly used for iteration, and
there's little need to get an array from zip, so that it is more
convenient to keep consistency with other enumerator returning
methods in Enumerable.
But use-case is more important than theoretical rationale. There are
several options we can take:
(1) easiest way - keeping 1.9 as it is.
no additional work required, but you have to stand the change
from 1.8; this might not be a good idea.
(2) 2nd easiest way - zip without block returns an array
this one is rather easy too. instead of returning Enumerator,
we can return a zipped array. The performance issue can also be
solved for this use-case.
(3) hardest way - (2) + honoring length of the receiver
I am not sure how to implement it yet. but if it is REALLY
needed this one is the way to go?
Any opinion?
matz.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Enumerable#zip Needs Love
2008-01-08 2:07 ` Yukihiro Matsumoto
@ 2008-01-08 4:50 ` James Gray
2008-01-08 5:06 ` Yukihiro Matsumoto
0 siblings, 1 reply; 15+ messages in thread
From: James Gray @ 2008-01-08 4:50 UTC (permalink / raw
To: ruby-core
On Jan 7, 2008, at 8:07 PM, Yukihiro Matsumoto wrote:
> Hi,
>
> In message "Re: Enumerable#zip Needs Love"
> on Tue, 8 Jan 2008 07:15:56 +0900, James Gray <james@grayproductions.net
> > writes:
>
> |Matz, at least this much of my proposal seems uncontested. Can you
> |tell us the reason for the new behavior?
>
> The rationales behind the changes were:
>
> (a) stopping at the shortest
>
> adopting the behavior from python where I took the idea of zip
> method. I saw some use cases that the shortest stop may
> helpful. Besides that it's much simpler to implement. But
> there's still room for you to persuade me.
Well, I don't want to sound like a broken record here, but the way I
see it is:
* With the 1.8 system, we easily can have it both ways. We can find
the bigger group and lead with that to save all data, or find the
shorter group and lead with it to trim data.
* Under 1.9 we lose data by default and it's challenging to save it
since all groups must be expanded to the same length.
> (b) return value
>
> My estimation was that zip was mostly used for iteration, and
> there's little need to get an array from zip, so that it is more
> convenient to keep consistency with other enumerator returning
> methods in Enumerable.
I can see your point here and Martin seemed to agree with you, but:
* An Array is a super set of Enumerable, so we gain more options
without losing anything.
* It seems to break a fair bit of 1.8 code. I can name three
libraries affected by the change off the top of my head.
* Performance seems like another good reason to do this, since you
said it would speed things up.
I promise I'm done pleading my case now. ;)
> But use-case is more important than theoretical rationale. There are
> several options we can take:
>
> (3) hardest way - (2) + honoring length of the receiver
>
> I am not sure how to implement it yet.
I don't understand. We had this in 1.8. Can we not go back to that
code?
James Edward Gray II
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Enumerable#zip Needs Love
2008-01-08 4:50 ` James Gray
@ 2008-01-08 5:06 ` Yukihiro Matsumoto
2008-01-08 14:23 ` James Gray
0 siblings, 1 reply; 15+ messages in thread
From: Yukihiro Matsumoto @ 2008-01-08 5:06 UTC (permalink / raw
To: ruby-core
Hi,
In message "Re: Enumerable#zip Needs Love"
on Tue, 8 Jan 2008 13:50:09 +0900, James Gray <james@grayproductions.net> writes:
|> (a) stopping at the shortest
|* With the 1.8 system, we easily can have it both ways. We can find
|the bigger group and lead with that to save all data, or find the
|shorter group and lead with it to trim data.
|* Under 1.9 we lose data by default and it's challenging to save it
|since all groups must be expanded to the same length.
Points taken.
|> (b) return value
|* An Array is a super set of Enumerable, so we gain more options
|without losing anything.
Although an array is a Enumerable, and implements every methods in
Enumerable, I still hesitate to call it "super set", just because it
introduces several restriction of Enumerable, for example non infinity
length. This is typical super set/sub set issue.
But using zip to create zipped array is certainly important use-case,
and consistency is not the primary goal of Ruby's design.
|* It seems to break a fair bit of 1.8 code. I can name three
|libraries affected by the change off the top of my head.
|* Performance seems like another good reason to do this, since you
|said it would speed things up.
Points taken.
|> But use-case is more important than theoretical rationale. There are
|> several options we can take:
|>
|> (3) hardest way - (2) + honoring length of the receiver
|>
|> I am not sure how to implement it yet.
|
|I don't understand. We had this in 1.8. Can we not go back to that
|code?
The internal was totally re-written in 1.9 using fiber, but that's OK.
It's our matter. In fact, I figured out how to do it while waiting
for your reply. And actually implemented it already. See attached
patch.
matz.
diff --git a/enum.c b/enum.c
index 04fade3..bf18e27 100644
--- a/enum.c
+++ b/enum.c
@@ -1347,6 +1347,36 @@ enum_each_with_index(int argc, VALUE *argv, VALUE obj)
static VALUE
+zip_a(VALUE val, NODE *memo, int argc, VALUE *argv)
+{
+ volatile VALUE result = memo->u1.value;
+ volatile VALUE args = memo->u2.value;
+ volatile VALUE tmp;
+ long idx = memo->u3.cnt++;
+ int i;
+
+ tmp = rb_ary_new2(RARRAY_LEN(args) + 1);
+ rb_ary_store(tmp, 0, val);
+ for (i=0; i<RARRAY_LEN(args); i++) {
+ rb_ary_push(tmp, rb_ary_entry(RARRAY_PTR(args)[i], idx));
+ }
+ rb_ary_push(result, tmp);
+ return Qnil;
+}
+
+static VALUE
+call_next(VALUE *v)
+{
+ return v[0] = rb_funcall(v[1], id_next, 0, 0);
+}
+
+static VALUE
+call_stop(VALUE *v)
+{
+ return v[0] = Qundef;
+}
+
+static VALUE
zip_i(VALUE val, NODE *memo, int argc, VALUE *argv)
{
volatile VALUE result = memo->u1.value;
@@ -1357,8 +1387,20 @@ zip_i(VALUE val, NODE *memo, int argc, VALUE *argv)
tmp = rb_ary_new2(RARRAY_LEN(args) + 1);
rb_ary_store(tmp, 0, enum_values_pack(argc, argv));
for (i=0; i<RARRAY_LEN(args); i++) {
- VALUE v = rb_funcall(RARRAY_PTR(args)[i], id_next, 0, 0);
- rb_ary_push(tmp, v);
+ if (NIL_P(RARRAY_PTR(args)[i])) {
+ rb_ary_push(tmp, Qnil);
+ }
+ else {
+ VALUE v[2];
+
+ v[1] = RARRAY_PTR(args)[i];
+ rb_rescue2(call_next, (VALUE)v, call_stop, (VALUE)v, rb_eStopIteration, 0);
+ if (v[0] == Qundef) {
+ RARRAY_PTR(args)[i] = Qnil;
+ v[0] = Qnil;
+ }
+ rb_ary_push(tmp, v[0]);
+ }
}
if (NIL_P(result)) {
rb_yield(tmp);
@@ -1369,12 +1411,6 @@ zip_i(VALUE val, NODE *memo, int argc, VALUE *argv)
return Qnil;
}
-static VALUE
-zip_b(NODE *memo)
-{
- return rb_block_call(memo->u3.value, id_each, 0, 0, zip_i, (VALUE)memo);
-}
-
/*
* call-seq:
* enum.zip(arg, ...) => enumerator
@@ -1400,19 +1436,30 @@ zip_b(NODE *memo)
static VALUE
enum_zip(int argc, VALUE *argv, VALUE obj)
{
- int i;
- VALUE result;
+ int i, block;
+ ID conv;
NODE *memo;
- for (i=0; i<argc; i++) {
- argv[i] = rb_funcall(argv[i], rb_intern("to_enum"), 1, ID2SYM(id_each));
+
+ if (!rb_block_given_p()) {
+ conv = rb_intern("to_a");
+ for (i=0; i<argc; i++) {
+ argv[i] = rb_funcall(argv[i], conv, 0, 0);
+ }
+ memo = rb_node_newnode(NODE_MEMO, rb_ary_new(), rb_ary_new4(argc, argv), 0);
+ rb_block_call(obj, id_each, 0, 0, zip_a, (VALUE)memo);
+
+ return memo->u1.value;
}
- RETURN_ENUMERATOR(obj, argc, argv);
- result = rb_block_given_p() ? Qnil : rb_ary_new();
- memo = rb_node_newnode(NODE_MEMO, result, rb_ary_new4(argc, argv), obj);
- rb_rescue2(zip_b, (VALUE)memo, 0, 0, rb_eStopIteration, (VALUE)0);
+ else {
+ conv = rb_intern("to_enum");
+ for (i=0; i<argc; i++) {
+ argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
+ }
+ memo = rb_node_newnode(NODE_MEMO, Qnil, rb_ary_new4(argc, argv), 0);
- return result;
+ return rb_block_call(obj, id_each, 0, 0, zip_i, (VALUE)memo);
+ }
}
static VALUE
diff --git a/enumerator.c b/enumerator.c
index 0474469..d9179db 100644
--- a/enumerator.c
+++ b/enumerator.c
@@ -365,9 +365,9 @@ enumerator_with_index(VALUE obj)
}
static VALUE
-next_ii(VALUE i, VALUE obj)
+next_ii(VALUE i, VALUE obj, int argc, VALUE *argv)
{
- rb_fiber_yield(1, &i);
+ rb_fiber_yield(argc, argv);
return Qnil;
}
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: Enumerable#zip Needs Love
2008-01-08 5:06 ` Yukihiro Matsumoto
@ 2008-01-08 14:23 ` James Gray
2008-01-08 14:34 ` Yukihiro Matsumoto
0 siblings, 1 reply; 15+ messages in thread
From: James Gray @ 2008-01-08 14:23 UTC (permalink / raw
To: ruby-core
On Jan 7, 2008, at 11:06 PM, Yukihiro Matsumoto wrote:
> Although an array is a Enumerable, and implements every methods in
> Enumerable, I still hesitate to call it "super set", just because it
> introduces several restriction of Enumerable, for example non infinity
> length.
Ah, I never considered infinite length iterators. Good example.
Well, that's two points against using an Array, so maybe we are better
of sticking with Enumerable. I do think we should still consider
going back to back to having the result size be the length of the
receiver though since I really feel like zip() was easier to make use
of, in that form.
> The internal was totally re-written in 1.9 using fiber, but that's OK.
> It's our matter. In fact, I figured out how to do it while waiting
> for your reply. And actually implemented it already. See attached
> patch.
Great. I'm glad you figured it out.
James Edward Gray II
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Enumerable#zip Needs Love
2008-01-08 14:23 ` James Gray
@ 2008-01-08 14:34 ` Yukihiro Matsumoto
2008-01-08 19:58 ` James Gray
0 siblings, 1 reply; 15+ messages in thread
From: Yukihiro Matsumoto @ 2008-01-08 14:34 UTC (permalink / raw
To: ruby-core
Hi,
In message "Re: Enumerable#zip Needs Love"
on Tue, 8 Jan 2008 23:23:16 +0900, James Gray <james@grayproductions.net> writes:
|Well, that's two points against using an Array, so maybe we are better
|of sticking with Enumerable. I do think we should still consider
|going back to back to having the result size be the length of the
|receiver though since I really feel like zip() was easier to make use
|of, in that form.
|
|> The internal was totally re-written in 1.9 using fiber, but that's OK.
|> It's our matter. In fact, I figured out how to do it while waiting
|> for your reply. And actually implemented it already. See attached
|> patch.
|
|Great. I'm glad you figured it out.
I've checked in. I think it works fine on both finite and infinite
enumerable objects, with sane performance (perhaps slower than 1.8
though).
matz.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Enumerable#zip Needs Love
2008-01-08 14:34 ` Yukihiro Matsumoto
@ 2008-01-08 19:58 ` James Gray
2008-01-08 23:19 ` Yukihiro Matsumoto
0 siblings, 1 reply; 15+ messages in thread
From: James Gray @ 2008-01-08 19:58 UTC (permalink / raw
To: ruby-core
On Jan 8, 2008, at 8:34 AM, Yukihiro Matsumoto wrote:
> Hi,
>
> In message "Re: Enumerable#zip Needs Love"
> on Tue, 8 Jan 2008 23:23:16 +0900, James Gray <james@grayproductions.net
> > writes:
>
> |Well, that's two points against using an Array, so maybe we are
> better
> |of sticking with Enumerable. I do think we should still consider
> |going back to back to having the result size be the length of the
> |receiver though since I really feel like zip() was easier to make use
> |of, in that form.
> |
> |> The internal was totally re-written in 1.9 using fiber, but
> that's OK.
> |> It's our matter. In fact, I figured out how to do it while waiting
> |> for your reply. And actually implemented it already. See attached
> |> patch.
> |
> |Great. I'm glad you figured it out.
>
> I've checked in. I think it works fine on both finite and infinite
> enumerable objects, with sane performance (perhaps slower than 1.8
> though).
Thanks for all your work on this Matz.
Do we need to update the documentation to reflect the change? I've
tried to do so in the patch below, but please double-check that I
described the new behavior correctly.
James Edward Gray II
Index: enum.c
===================================================================
--- enum.c (revision 14958)
+++ enum.c (working copy)
@@ -1400,18 +1400,19 @@
*
* Takes one element from <i>enum</i> and merges corresponding
* elements from each <i>args</i>. This generates a sequence of
- * <em>n</em>-element arrays, where <em>n</em> is one more that the
- * count of arguments. The length of the sequence is truncated to
- * the size of the shortest argument (or <i>enum</i>). If a block
- * given, it is invoked for each output array, otherwise an array of
- * arrays is returned.
+ * <em>n</em>-element arrays, where <em>n</em> is one more than the
+ * count of arguments. The length of the resulting sequence will be
+ * <code>enum#size</code. If the size of any argument is less than
+ * <code>enum#size</code>, <code>nil</code> values are supplied. If
+ * a block is given, it is invoked for each output array, otherwise
+ * an array of arrays is returned.
*
* a = [ 4, 5, 6 ]
* b = [ 7, 8, 9 ]
*
* [1,2,3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
* [1,2].zip(a,b) #=> [[1, 4, 7], [2, 5, 8]]
- * a.zip([1,2],[8]) #=> [[4,1,8]]
+ * a.zip([1,2],[8]) #=> [[4, 1, 8], [5, 2, nil], [6, nil,
nil]]
*
*/
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Enumerable#zip Needs Love
2008-01-08 19:58 ` James Gray
@ 2008-01-08 23:19 ` Yukihiro Matsumoto
2008-01-08 23:43 ` James Gray
[not found] ` <335e48a90801101104o177dea71m7cdd523a440055a0@mail.gmail.com>
0 siblings, 2 replies; 15+ messages in thread
From: Yukihiro Matsumoto @ 2008-01-08 23:19 UTC (permalink / raw
To: ruby-core
Hi,
In message "Re: Enumerable#zip Needs Love"
on Wed, 9 Jan 2008 04:58:11 +0900, James Gray <james@grayproductions.net> writes:
|Do we need to update the documentation to reflect the change? I've
|tried to do so in the patch below, but please double-check that I
|described the new behavior correctly.
I guess the description is correct. Could you check in?
matz.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Enumerable#zip Needs Love
2008-01-08 23:19 ` Yukihiro Matsumoto
@ 2008-01-08 23:43 ` James Gray
[not found] ` <335e48a90801101104o177dea71m7cdd523a440055a0@mail.gmail.com>
1 sibling, 0 replies; 15+ messages in thread
From: James Gray @ 2008-01-08 23:43 UTC (permalink / raw
To: ruby-core
On Jan 8, 2008, at 5:19 PM, Yukihiro Matsumoto wrote:
> Hi,
>
> In message "Re: Enumerable#zip Needs Love"
> on Wed, 9 Jan 2008 04:58:11 +0900, James Gray <james@grayproductions.net
> > writes:
>
> |Do we need to update the documentation to reflect the change? I've
> |tried to do so in the patch below, but please double-check that I
> |described the new behavior correctly.
>
> I guess the description is correct. Could you check in?
Done.
Thanks Matz.
James Edward Gray II
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Enumerable#zip Needs Love
[not found] ` <335e48a90801101104o177dea71m7cdd523a440055a0@mail.gmail.com>
@ 2008-01-10 19:16 ` James Gray
[not found] ` <335e48a90801101310i2525b9fcl287108cd68d3bcba@mail.gmail.com>
0 siblings, 1 reply; 15+ messages in thread
From: James Gray @ 2008-01-10 19:16 UTC (permalink / raw
To: ruby-core
On Jan 10, 2008, at 1:03 PM, Robert Dober wrote:
> Sorry for asking a stupid question: Are we not getting an Enumerator
> anymore for a call of #zip without any block?
Correct.
> If so, would that not be the only method in Enumerable not doing so.
No. Here's my list from earlier in this thread:
all?(), any?(), count(), drop(), inject()/reduce(),
none?(), one?(), sort(), and take()
James Edward Gray II
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Enumerable#zip Needs Love
[not found] ` <335e48a90801101310i2525b9fcl287108cd68d3bcba@mail.gmail.com>
@ 2008-01-10 21:26 ` James Gray
0 siblings, 0 replies; 15+ messages in thread
From: James Gray @ 2008-01-10 21:26 UTC (permalink / raw
To: ruby-core
On Jan 10, 2008, at 3:10 PM, Robert Dober wrote:
> On Jan 10, 2008 8:16 PM, James Gray <james@grayproductions.net> wrote:
>> count(),
> not in revision 14709, did this change too?
Ah, it doesn't return an Enumerable if passed an argument.
James Edward Gray II
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2008-01-10 21:29 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-03 22:05 Enumerable#zip Needs Love James Gray
2008-01-04 6:11 ` Martin Duerst
2008-01-04 14:22 ` James Gray
2008-01-04 17:52 ` Rick DeNatale
2008-01-07 22:15 ` James Gray
2008-01-08 2:07 ` Yukihiro Matsumoto
2008-01-08 4:50 ` James Gray
2008-01-08 5:06 ` Yukihiro Matsumoto
2008-01-08 14:23 ` James Gray
2008-01-08 14:34 ` Yukihiro Matsumoto
2008-01-08 19:58 ` James Gray
2008-01-08 23:19 ` Yukihiro Matsumoto
2008-01-08 23:43 ` James Gray
[not found] ` <335e48a90801101104o177dea71m7cdd523a440055a0@mail.gmail.com>
2008-01-10 19:16 ` James Gray
[not found] ` <335e48a90801101310i2525b9fcl287108cd68d3bcba@mail.gmail.com>
2008-01-10 21:26 ` James Gray
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).