[ruby-core:95869] [Ruby master Bug#16351] Why do Keyword arguments to initialize allocate a Hash, but not for other methods?

From: nobu@...
Date: 2019-11-17 14:16:50 UTC
List: ruby-core #95869
Issue #16351 has been updated by nobu (Nobuyoshi Nakada).

Status changed from Open to Closed
Description updated

`FooWithKeyword#initialize` method is not called directly, but via `Class#new`.
A `Hash` is needed to delegate the keyword arguments.
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)
```

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

* 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:[email protected]?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>

In This Thread

Prev Next