Issue #10560 has been updated by Nobuyoshi Nakada.


David MacMahon wrote:
> Maybe this could become a feature request to allow `<OP>=` to be methods instead of just syntactic sugar?

Of course you can.

I believe it will be rejected soon, however.

----------------------------------------
misc #10560: confusion between x=x+y, x+=y, x.concat(y) and y.each{|z| x<<z}
https://bugs.ruby-lang.org/issues/10560#change-50302

* Author: Michal Papis
* Status: Assigned
* Priority: Normal
* Assignee: Zachary Scott
* Category: doc
* Target version: current: 2.2.0
----------------------------------------
while discussing a ticket I have noticed that there is no documentation for `+=`

I was expecting `+=` to behave as `concat` but instead it behaves as `x=x+y` which for every operation clones the array and updates the variable with new value so it behaves similarly to `x=x.dup.concat(y)` and is slightly faster, but using plane `x.concat(y)` is a lot faster from both `each<<` and `+=`

I would either like to get:

 - updated docs that describe concept of `+=` and show the difference from `concat`
 - or change `+=` to use `concat` which is faster - and add docs ;) (I would expect `+=` to use `concat` when available)

here is a test:

    require 'benchmark'
    
    rep = 10_000
    
    Benchmark.bmbm do |x|
      {
        1..25 => [],
        "a".."z" => "",
      }.each do |base, storage|
    
        base = base.to_a
        basej = base
        class_name = storage.class.to_s
    
        x.report(class_name+'#concat') do
          a = storage.dup
          basej = base.join if storage == ""
          rep.times { a.concat(basej) }
        end
    
        x.report(class_name+'#<<') do
          a = storage.dup
          basej = base.join if storage == ""
          rep.times { base.each { |e| a << e } }
        end
    
        x.report(class_name+'#+=') do
          a = storage.dup
          basej = base.join if storage == ""
          rep.times { a += basej }
        end
    
        x.report(class_name+'#dup.concat') do
          a = storage.dup
          basej = base.join if storage == ""
          rep.times { a = a.dup.concat(basej) }
        end
    
      end
    end


and here are results on my machine:

                            user     system      total        real
    Array#concat        0.000000   0.000000   0.000000 (  0.001422)
    Array#<<            0.020000   0.000000   0.020000 (  0.014356)
    Array#+=            1.270000   0.230000   1.500000 (  1.498558)
    Array#dup.concat    2.720000   0.190000   2.910000 (  2.915701)
    String#concat       0.000000   0.000000   0.000000 (  0.001072)
    String#<<           0.030000   0.000000   0.030000 (  0.025828)
    String#+=           0.130000   0.010000   0.140000 (  0.135143)
    String#dup.concat   0.210000   0.020000   0.230000 (  0.227470)




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