Issue #16351 has been updated by mame (Yusuke Endoh).


nobu (Nobuyoshi Nakada) wrote:
> By changing the last calling line as the following with making that `initialize` method public, you could observe the same numbers as `FooWithPlainParams`.
> ```ruby
>     FooWithKeyword.allocate.initialize(a: 1, b: 2, c: 3)
> ```

I'd like to add a note: `allocate.initialize` just demonstrates the reason for the behavior.  Never do write that in your code.

Currently, @ko1 is addressing this kind of issue fundamentally by a mechanism to write almost all builtin methods in Ruby.  If Class#new is written in Ruby, and if a lazy allocation of keyword rest hash is introduced, the extra allocation will be removed.

----------------------------------------
Bug #16351: Why do Keyword arguments to initialize allocate a Hash, but not for other methods?
https://bugs.ruby-lang.org/issues/16351#change-82705

* Author: brunoe (Bruno Escherl)
* Status: Closed
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.7.0dev (2019-11-17T04:12:06Z trunk a8e4a9f03a) [x86_64-darwin19]
* Backport: 2.5: UNKNOWN, 2.6: UNKNOWN
----------------------------------------
Hello, while working on improving memory allocations in one of my apps, I stumbled upon the following behavior. I measured three different ways of passing variables to a new `Object`, using plain params, using a hash and using keyword arguments.

```ruby
class FooWithPlainParams
  def initialize(a, b, c)
    @a = a
    @b = b
    @c = c
  end
end

class FooWithOptionsHash
  def initialize(options = {})
    @a = options[:a]
    @b = options[:b]
    @c = options[:c]
  end
end

class FooWithKeyword
  def initialize(a:, b:, c:)
    @a = a
    @b = b
    @c = c
  end
end
```

I used memory_profiler gem to measure the allocations with the attached script, calling new 100 times, using ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin19]

`FooWithPlainParams` not surprisingly just reported "Total allocated: 4000 bytes (100 objects)".
`FooWithOptionsHash` reported "Total allocated: 27200 bytes (200 objects)" with 100 `Hash` allocations. This makes sense, since the params are passed on as a `Hash`.
`FooWithKeywordArguments` reported "Total allocated: 50400 bytes (300 objects)" with 200 `Hash` allocations, which is a bit surprising.

After that I checked out ruby-head and there `FooWithKeywordArguments.new` reports only 100 `Hash` allocations as `FooWithOptionsHash`. So that part seems to be fixed.

What surprised me so was, that using the same way of passing parameters in another method, resulted in no allocated Hash according to memory_profiler gem.

```ruby
class FooWithKeyword
  def foo(d:, e:, f:)
    @d = d; @e = e; @f = f
  end
end
```

Calling `foo(d: 4, e: 5, f: 6)` on a `FooWithKeyword` object, does not show any allocations.

What is the difference here between `foo` and `initialize`?

---Files--------------------------------
profile_foo.rb (837 Bytes)
profile_initialize.rb (847 Bytes)


-- 
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>