Issue #14380 has been updated by taw (Tomasz Wegrzanowski).


marcandre (Marc-Andre Lafortune) wrote:
> I raised this issue previously https://bugs.ruby-lang.org/issues/13583#note-8
> 
> This is a spec change. Moreover it introduces incompatibilities with ActiveSupport.

I'd say that ActiveSupport is testing group for possible new ruby features,
and when getting them into ruby core library, it's good time to clean up their edge cases.


----------------------------------------
Bug #14380: Expected transform_keys! to work just as transform_keys, but it doesn't
https://bugs.ruby-lang.org/issues/14380#change-70146

* Author: taw (Tomasz Wegrzanowski)
* Status: Open
* Priority: Normal
* Assignee: matz (Yukihiro Matsumoto)
* Target version: 
* ruby -v: ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin17]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
This seriously violates the Principle of Least Surprise to me:

    {1 => :a, -1 => :b}.transform_keys{|k| -k} #=> {-1=>:a, 1=>:b}
    {1 => :a, -1 => :b}.transform_keys!{|k| -k} # => {1=>:a}

    # This fails:
    ht=(1..10).map{|k| [k,k]}.to_h; ht.transform_keys(&:succ) # => {2=>1, 3=>2, 4=>3, 5=>4, 6=>5, 7=>6, 8=>7, 9=>8, 10=>9, 11=>10}
    ht=(1..10).map{|k| [k,k]}.to_h; ht.transform_keys!(&:succ) # => {11=>1}

    # This code with same issue works just because of key ordering:
    ht=(1..10).map{|k| [k,k]}.to_h; ht.transform_keys(&:pred) #=> {0=>1, 1=>2, 2=>3, 3=>4, 4=>5, 5=>6, 6=>7, 7=>8, 8=>9, 9=>10}
    ht=(1..10).map{|k| [k,k]}.to_h; ht.transform_keys!(&:pred) #=> {0=>1, 1=>2, 2=>3, 3=>4, 4=>5, 5=>6, 6=>7, 7=>8, 8=>9, 9=>10}

Of course in these examples it's very easy to see the problem, but in bigger programs it could be really difficult.

If the implementation instead did equivalent of:

    class Hash
      def transform_values!(&block)
        replace transform_values(&block)
      end
    end

it would be much less surprising.

`Hash#transform_keys` / `Hash#transform_keys!` inherently require that resulting values don't collide, but in these examples it works in surprising ways even though there's no collision between results.



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>