Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #3592 (new defect)

Opened 3 years ago

Last modified 1 year ago

[PATCH] fix the Enumerable.reject and findAll methods

Reported by: aljoscha@weisshuhn.de Assigned to: mislav
Priority: normal Milestone:
Component: Prototype Version: 1.0.0
Severity: normal Keywords: Enumerable findAll reject
Cc: rubyonrails@brainsick.com, mislav, Tobie

Description

The Enumerable mixin class does not properly respect the mixees internal format. So the reject and findAll methods, used with Hashes return Arrays instead of Hashes.

In Ruby (from which the inspiration for the Enumerable Mixin stems), the reject method sure does return a hash, not an array, when acting on an hash: irb(main):001:0> a = {:a => 1, :b => 2, :c => 1, :d => 3} => {:b=>2, :c=>1, :a=>1, :d=>3} irb(main):002:0> b = a.reject{|k,v| v==1} => {:b=>2, :d=>3}

The patch requires all classes that want to mixin Enumerable to define two more methods similar to _each: _new, which return s an empty object of that class and _add, that adds an element. The Enumerable thus makes no more assumptions about the internal structure of its mixee class.

Examples (before and after fix) are given below.

    var a = $H({a:1, b:2, c:1, d:3});
    document.writeln(a.inspect().escapeHTML());

    => #<Hash:{'a': 1, 'b': 2, 'c': 1, 'd': 3}>

    var b = a.reject(function(val){ return (val[1]==1) });
    document.writeln(b.inspect().escapeHTML());
 

    1.4.0   => [['b', 2], ['d', 3]]
    patched => #<Hash:{'b': 2, 'd': 3}>


    var c = b.findAll(function(val){ return (val[0]=='d') });
    document.writeln(c.inspect().escapeHTML());
 

    1.4.0   => [['b', 2], ['d', 3]]
    patched => #<Hash:{'d': 3}>

Attachments

prototype-1.4.0-enum.diff (0.6 kB) - added by aljoscha@weisshuhn.de on 01/24/06 14:56:38.
Patch vor Enumerable.reject and Enumerable.findAll
prototype-1.4.0-enum.2.diff (1.4 kB) - added by aljoscha@weisshuhn.de on 02/07/06 12:16:59.
I hope this is better. Also used the diff -u option.
prototype-1.4.0-enum.3.diff (1.4 kB) - added by aljoscha@weisshuhn.de on 02/08/06 09:24:42.
Very well, removed the brackets. What is XPATCH supposed to mean? "Not a patch unless brackets removed?"
patch_3592.txt (2.9 kB) - added by aljoscha on 11/06/06 11:18:04.
Patch for latest SVN checkout, including enumerable.js, hash.js, array.js and test/unit/hash.html
patch_3592.diff (2.9 kB) - added by aljoscha on 11/20/06 10:00:33.
Patch for latest trunk (5587)

Change History

01/24/06 14:56:38 changed by aljoscha@weisshuhn.de

  • attachment prototype-1.4.0-enum.diff added.

Patch vor Enumerable.reject and Enumerable.findAll

01/24/06 15:00:57 changed by anonymous

  • summary changed from fixes the Enumerable.reject and findAll methods to [PATCH] fix the Enumerable.reject and findAll methods.

02/06/06 23:14:10 changed by rubyonrails@brainsick.com

  • cc set to rubyonrails@brainsick.com.

Your patch is more likely to be accepted if you follow the existing coding style.

The developers don't wrap one-line blocks in {}. They also put a space between () and { for functions. The $H() and $A() functions you're using can take empty parameter lists and still return the objects you want.

(Note: I'm not affiliated with Prototype; just an interested developer.)

02/07/06 12:16:59 changed by aljoscha@weisshuhn.de

  • attachment prototype-1.4.0-enum.2.diff added.

I hope this is better. Also used the diff -u option.

02/07/06 23:53:57 changed by rubyonrails@brainsick.com

  • summary changed from [PATCH] fix the Enumerable.reject and findAll methods to [XPATCH] fix the Enumerable.reject and findAll methods.

From a code consistancy standpoint:

+      if (!iterator(value, index)){
+        results._add(value, index);
+      }

Should really be:

+      if (!iterator(value, index))
+        results._add(value, index);

02/08/06 09:24:42 changed by aljoscha@weisshuhn.de

  • attachment prototype-1.4.0-enum.3.diff added.

Very well, removed the brackets. What is XPATCH supposed to mean? "Not a patch unless brackets removed?"

02/08/06 09:26:37 changed by anonymous

  • summary changed from [XPATCH] fix the Enumerable.reject and findAll methods to [PATCH] fix the Enumerable.reject and findAll methods.

02/08/06 11:48:52 changed by rubyonrails@brainsick.com

  • keywords set to Enumerable findAll reject.

Patches that has unanswered questions or need work in general are moved to Needy Patches (their prefix is [XPATCH]). Performance patches reside on the Performance Patches page (their prefix is [PPATCH]).

04/11/06 09:56:09 changed by aljoscha@weisshuhn.de

There is another problem with hashes, namely that functions cannot be values in hashes, and a rather mediocre fix described here: http://dev.rubyonrails.org/ticket/4689

09/04/06 22:43:16 changed by madrobby

  • status changed from new to closed.
  • resolution set to untested.

10/10/06 12:22:04 changed by aljoscha

  • status changed from closed to reopened.
  • resolution deleted.

A testcase for the patch can be found here: http://www.presber.net/ticket3592.html

If a different type of testcase is needed, I will be happy to supply it.

11/04/06 20:04:41 changed by mislav

  • cc changed from rubyonrails@brainsick.com to rubyonrails@brainsick.com, mislav.

Testcase should be a patch for test/unit/enumerable.html or hash.html

That way new tests are mixed in with the old so the tester can be sure nothing else is broken by this change... that's the point of unit tests

11/06/06 11:18:04 changed by aljoscha

  • attachment patch_3592.txt added.

Patch for latest SVN checkout, including enumerable.js, hash.js, array.js and test/unit/hash.html

11/20/06 10:00:33 changed by aljoscha

  • attachment patch_3592.diff added.

Patch for latest trunk (5587)

12/20/06 08:17:49 changed by Tobie

  • cc changed from rubyonrails@brainsick.com, mislav to rubyonrails@brainsick.com, mislav, Tobie.

duplicates with #6853

02/07/07 02:36:19 changed by mislav

  • owner changed from sam@conio.net to mislav.
  • status changed from reopened to new.

02/07/07 13:44:46 changed by aljoscha

An explanation regarding #6853.

Enumerability is a concept. It implies possibilities to recect, find, count ... elements of a given Enumerable based on their properties.

The implementation of the general concept of "finding" or "rejecting" or "injecting" belongs into Enumerable and cannot make any assumptions about the internal structure of the classes that later want to mix in Enumerable to become - well - enumerable. Enumerable can, however, make requirements for those classes to implement certain methods and such dividing the general part from the specific.

As proposed by this ticket, implementing _each() is not enough. In order to return the result Hash (or Range, or directed graph, or...) the specific class has to provide means to create an empty instance (via _new()) and to add elements (via _add). These names are proposed for their brevity.

As it is implemented now, Enumerables "filters" like reject are able to give back only Arrays, because the implement "creating" and "adding" as an array. This should be generalized to allow for any Enumerable.

Ticket #6853 proposes to reimplement rejection specifically for Hashes. This, imho, is exactly the way not to go, because it takes away the generality Enumerable seeks to introduce.

06/18/07 23:13:38 changed by savetheclocktower

There's a complicating factor here: the behavior of Enumerable#reject and Enumerable#select in Ruby is even more perplexing. I'll let irb demonstrate:

>> h = { 'foo' => 'bar', 'baz' => 'thud' }
=> {"baz"=>"thud", "foo"=>"bar"}
>> h.reject { |k, v| k == 'foo' }
=> {"baz"=>"thud"}
>> h.select { |k, v| k == 'foo' }
=> [["foo", "bar"]]

I think select and reject should return their own type for consistency. But I also think that they should behave as much like their Ruby counterparts as possible. Of course, Ruby's existing behavior here is ridiculous and should not be emulated. I'm stuck here.

06/18/07 23:40:04 changed by mislav

I think they should return their own type, no matter what. Who cares about Ruby oddities :P

01/02/08 13:15:44 changed by wackimonki

I'm new to all this. Can I ask what's going on with this patch?

It would be great seeing this fix in prototype.

01/02/08 13:45:42 changed by wackimonki

I tried manually patching the latest Prototype without success. I was trying it with a hash.

I could do this with the returned hash obj:

hash.key1;
hash.key1;

These had empty outputs:

hash.size();
hash.toQueryString();

In case this helps anyone, I am now using a workaround to convert array to hash:

hash = $H({});
my_array.each( function(pair) { hash.set(pair[0], pair[1]);});

01/25/08 05:40:59 changed by kangax

Oh, great 1.9 fixes this weird annoyance http://eigenclass.org/hiki.rb?Changes+in+Ruby+1.9#l90

02/08/08 15:09:00 changed by aljoscha

Ruby 1.9 that is.