<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/test/ruby/test_keyword.rb, branch v3_2_11</title>
<subtitle>The Ruby Programming Language</subtitle>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/'/>
<entry>
<title>Rename method name in keyword test from y to yo</title>
<updated>2022-09-26T19:00:40+00:00</updated>
<author>
<name>Jeremy Evans</name>
<email>code@jeremyevans.net</email>
</author>
<published>2022-09-26T17:53:45+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=b39690df3a90a838cdb2de71e70a20651ebafaf4'/>
<id>b39690df3a90a838cdb2de71e70a20651ebafaf4</id>
<content type='text'>
Kernel#y is defined by psych/yaml, which causes occasional
nondeterministic problems with this test when doing parallel testing.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Kernel#y is defined by psych/yaml, which causes occasional
nondeterministic problems with this test when doing parallel testing.
</pre>
</div>
</content>
</entry>
<entry>
<title>test/ruby/test_keyword.rb: Prevent warning: assigned but unused variable</title>
<updated>2022-04-11T01:05:16+00:00</updated>
<author>
<name>Yusuke Endoh</name>
<email>mame@ruby-lang.org</email>
</author>
<published>2022-04-11T01:05:16+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=44a911a293ca6448f9e029e22492e78a1828a16b'/>
<id>44a911a293ca6448f9e029e22492e78a1828a16b</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Unflag a splatted flagged hash if the method doesn't use ruby2_keywords</title>
<updated>2022-04-05T09:42:02+00:00</updated>
<author>
<name>Jeremy Evans</name>
<email>code@jeremyevans.net</email>
</author>
<published>2022-03-11T21:49:36+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=752c3dad989bb66e4be61911a82fed992067bdc3'/>
<id>752c3dad989bb66e4be61911a82fed992067bdc3</id>
<content type='text'>
For a method such as:

  def foo(*callee_args) end

If this method is called with a flagged hash (created by a method
flagged with ruby2_keywords), this previously passed the hash
through without modification.  With this change, it acts as if the
last hash was passed as keywords, so a call to:

  foo(*caller_args)

where the last element of caller_args is a flagged hash, will be
treated as:

  foo(*caller_args[0...-1], **caller_args[-1])

As a result, inside foo, callee_args[-1] is an unflagged duplicate
of caller_args[-1] (all other elements of callee_args match
caller_args).

Fixes [Bug #18625]
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
For a method such as:

  def foo(*callee_args) end

If this method is called with a flagged hash (created by a method
flagged with ruby2_keywords), this previously passed the hash
through without modification.  With this change, it acts as if the
last hash was passed as keywords, so a call to:

  foo(*caller_args)

where the last element of caller_args is a flagged hash, will be
treated as:

  foo(*caller_args[0...-1], **caller_args[-1])

As a result, inside foo, callee_args[-1] is an unflagged duplicate
of caller_args[-1] (all other elements of callee_args match
caller_args).

Fixes [Bug #18625]
</pre>
</div>
</content>
</entry>
<entry>
<title>Do not autosplat array in block call just because keywords accepted</title>
<updated>2022-03-30T18:03:56+00:00</updated>
<author>
<name>Jeremy Evans</name>
<email>code@jeremyevans.net</email>
</author>
<published>2022-03-30T18:03:56+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=fbaadd1cfe7fbfd1b904f193f99d7c845a6ed804'/>
<id>fbaadd1cfe7fbfd1b904f193f99d7c845a6ed804</id>
<content type='text'>
If the block only accepts a single positional argument plus keywords,
then do not autosplat.  Still autosplat if the block accepts more
than one positional argument in addition to keywords.

Autosplatting a single positional argument plus keywords made sense
in Ruby 2, since a final positional hash could be used as keywords,
but it does not make sense in Ruby 3.

Fixes [Bug #18633]</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
If the block only accepts a single positional argument plus keywords,
then do not autosplat.  Still autosplat if the block accepts more
than one positional argument in addition to keywords.

Autosplatting a single positional argument plus keywords made sense
in Ruby 2, since a final positional hash could be used as keywords,
but it does not make sense in Ruby 3.

Fixes [Bug #18633]</pre>
</div>
</content>
</entry>
<entry>
<title>Adds mixed hash value and value omission tests</title>
<updated>2021-09-13T04:54:03+00:00</updated>
<author>
<name>Brandon Weaver</name>
<email>keystonelemur@gmail.com</email>
</author>
<published>2021-09-13T03:34:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=4676921730bd257c234396fd9134ae9876043756'/>
<id>4676921730bd257c234396fd9134ae9876043756</id>
<content type='text'>
Introduces specification tests for mixed values and value omissions for
Hashes and keyword arguments, such as `{ a:, b:, c: 3 }`.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Introduces specification tests for mixed values and value omissions for
Hashes and keyword arguments, such as `{ a:, b:, c: 3 }`.
</pre>
</div>
</content>
</entry>
<entry>
<title>Add documentation and tests for keyword argument value omission</title>
<updated>2021-09-11T11:23:36+00:00</updated>
<author>
<name>Shugo Maeda</name>
<email>shugo@ruby-lang.org</email>
</author>
<published>2021-09-11T11:23:36+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=297f9b8d4c4502aa2ba0eccf93dfce215a7b6dfe'/>
<id>297f9b8d4c4502aa2ba0eccf93dfce215a7b6dfe</id>
<content type='text'>
[Feature #14579]
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
[Feature #14579]
</pre>
</div>
</content>
</entry>
<entry>
<title>Add back checks for empty kw splat with tests (#4405)</title>
<updated>2021-04-24T02:17:20+00:00</updated>
<author>
<name>Alan Wu</name>
<email>XrXr@users.noreply.github.com</email>
</author>
<published>2021-04-24T02:17:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=dee58d7ae7b75971f349f2217007fdf45d1ea23d'/>
<id>dee58d7ae7b75971f349f2217007fdf45d1ea23d</id>
<content type='text'>
This reverts commit a224ce8150f2bc687cf79eb415c931d87a4cd247.
Turns out the checks are needed to handle splatting an array with an
empty ruby2 keywords hash.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This reverts commit a224ce8150f2bc687cf79eb415c931d87a4cd247.
Turns out the checks are needed to handle splatting an array with an
empty ruby2 keywords hash.</pre>
</div>
</content>
</entry>
<entry>
<title>Fixed premature return</title>
<updated>2021-01-19T08:59:37+00:00</updated>
<author>
<name>Nobuyoshi Nakada</name>
<email>nobu@ruby-lang.org</email>
</author>
<published>2021-01-19T07:40:46+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=eeacdcb9a073c7d8ad703e0dc9faf229a5ebbe3c'/>
<id>eeacdcb9a073c7d8ad703e0dc9faf229a5ebbe3c</id>
<content type='text'>
After setting ruby2_keywords for bmethod, the rest of arguments
had been ignored. [Bug #17558]
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
After setting ruby2_keywords for bmethod, the rest of arguments
had been ignored. [Bug #17558]
</pre>
</div>
</content>
</entry>
<entry>
<title>Dup kwrest hash when merging other keyword arguments [Bug #17481]</title>
<updated>2020-12-27T16:52:18+00:00</updated>
<author>
<name>Nobuyoshi Nakada</name>
<email>nobu@ruby-lang.org</email>
</author>
<published>2020-12-27T16:38:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=c8010fcec016ee89aa0c45fe31094b2db0023e5c'/>
<id>c8010fcec016ee89aa0c45fe31094b2db0023e5c</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Reduce allocations for keyword argument hashes</title>
<updated>2020-03-17T19:09:43+00:00</updated>
<author>
<name>Jeremy Evans</name>
<email>code@jeremyevans.net</email>
</author>
<published>2020-02-24T20:05:07+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=d2c41b1bff1f3102544bb0d03d4e82356d034d33'/>
<id>d2c41b1bff1f3102544bb0d03d4e82356d034d33</id>
<content type='text'>
Previously, passing a keyword splat to a method always allocated
a hash on the caller side, and accepting arbitrary keywords in
a method allocated a separate hash on the callee side.  Passing
explicit keywords to a method that accepted a keyword splat
did not allocate a hash on the caller side, but resulted in two
hashes allocated on the callee side.

This commit makes passing a single keyword splat to a method not
allocate a hash on the caller side.  Passing multiple keyword
splats or a mix of explicit keywords and a keyword splat still
generates a hash on the caller side.  On the callee side,
if arbitrary keywords are not accepted, it does not allocate a
hash.  If arbitrary keywords are accepted, it will allocate a
hash, but this commit uses a callinfo flag to indicate whether
the caller already allocated a hash, and if so, the callee can
use the passed hash without duplicating it.  So this commit
should make it so that a maximum of a single hash is allocated
during method calls.

To set the callinfo flag appropriately, method call argument
compilation checks if only a single keyword splat is given.
If only one keyword splat is given, the VM_CALL_KW_SPLAT_MUT
callinfo flag is not set, since in that case the keyword
splat is passed directly and not mutable.  If more than one
splat is used, a new hash needs to be generated on the caller
side, and in that case the callinfo flag is set, indicating
the keyword splat is mutable by the callee.

In compile_hash, used for both hash and keyword argument
compilation, if compiling keyword arguments and only a
single keyword splat is used, pass the argument directly.

On the caller side, in vm_args.c, the callinfo flag needs to
be recognized and handled.  Because the keyword splat
argument may not be a hash, it needs to be converted to a
hash first if not.  Then, unless the callinfo flag is set,
the hash needs to be duplicated.  The temporary copy of the
callinfo flag, kw_flag, is updated if a hash was duplicated,
to prevent the need to duplicate it again.  If we are
converting to a hash or duplicating a hash, we need to update
the argument array, which can including duplicating the
positional splat array if one was passed.  CALLER_SETUP_ARG
and a couple other places needs to be modified to handle
similar issues for other types of calls.

This includes fairly comprehensive tests for different ways
keywords are handled internally, checking that you get equal
results but that keyword splats on the caller side result in
distinct objects for keyword rest parameters.

Included are benchmarks for keyword argument calls.
Brief results when compiled without optimization:

  def kw(a: 1) a end
  def kws(**kw) kw end
  h = {a: 1}

  kw(a: 1)       # about same
  kw(**h)        # 2.37x faster
  kws(a: 1)      # 1.30x faster
  kws(**h)       # 2.19x faster
  kw(a: 1, **h)  # 1.03x slower
  kw(**h, **h)   # about same
  kws(a: 1, **h) # 1.16x faster
  kws(**h, **h)  # 1.14x faster
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Previously, passing a keyword splat to a method always allocated
a hash on the caller side, and accepting arbitrary keywords in
a method allocated a separate hash on the callee side.  Passing
explicit keywords to a method that accepted a keyword splat
did not allocate a hash on the caller side, but resulted in two
hashes allocated on the callee side.

This commit makes passing a single keyword splat to a method not
allocate a hash on the caller side.  Passing multiple keyword
splats or a mix of explicit keywords and a keyword splat still
generates a hash on the caller side.  On the callee side,
if arbitrary keywords are not accepted, it does not allocate a
hash.  If arbitrary keywords are accepted, it will allocate a
hash, but this commit uses a callinfo flag to indicate whether
the caller already allocated a hash, and if so, the callee can
use the passed hash without duplicating it.  So this commit
should make it so that a maximum of a single hash is allocated
during method calls.

To set the callinfo flag appropriately, method call argument
compilation checks if only a single keyword splat is given.
If only one keyword splat is given, the VM_CALL_KW_SPLAT_MUT
callinfo flag is not set, since in that case the keyword
splat is passed directly and not mutable.  If more than one
splat is used, a new hash needs to be generated on the caller
side, and in that case the callinfo flag is set, indicating
the keyword splat is mutable by the callee.

In compile_hash, used for both hash and keyword argument
compilation, if compiling keyword arguments and only a
single keyword splat is used, pass the argument directly.

On the caller side, in vm_args.c, the callinfo flag needs to
be recognized and handled.  Because the keyword splat
argument may not be a hash, it needs to be converted to a
hash first if not.  Then, unless the callinfo flag is set,
the hash needs to be duplicated.  The temporary copy of the
callinfo flag, kw_flag, is updated if a hash was duplicated,
to prevent the need to duplicate it again.  If we are
converting to a hash or duplicating a hash, we need to update
the argument array, which can including duplicating the
positional splat array if one was passed.  CALLER_SETUP_ARG
and a couple other places needs to be modified to handle
similar issues for other types of calls.

This includes fairly comprehensive tests for different ways
keywords are handled internally, checking that you get equal
results but that keyword splats on the caller side result in
distinct objects for keyword rest parameters.

Included are benchmarks for keyword argument calls.
Brief results when compiled without optimization:

  def kw(a: 1) a end
  def kws(**kw) kw end
  h = {a: 1}

  kw(a: 1)       # about same
  kw(**h)        # 2.37x faster
  kws(a: 1)      # 1.30x faster
  kws(**h)       # 2.19x faster
  kw(a: 1, **h)  # 1.03x slower
  kw(**h, **h)   # about same
  kws(a: 1, **h) # 1.16x faster
  kws(**h, **h)  # 1.14x faster
</pre>
</div>
</content>
</entry>
</feed>
