https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112011-10-24T09:53:09ZRuby Issue Tracking SystemRuby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215082011-10-24T09:53:09Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>Hi,</p>
<p>In message "Re: <a href="/issues/5474">[ruby-core:40290]</a> [ruby-trunk - Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/5474">#5474</a>][Assigned] keyword argument"<br>
on Sun, 23 Oct 2011 21:53:58 +0900, Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a> writes:</p>
<p>|- it raises an TypeError when unknown keyword is given<br>
|<br>
| create_point(2, 3, style: "solid")<br>
| #=> unknown keyword (TypeError)</p>
<p>I think it should be ArgumentError instead of TypeError.</p>
<p>|An alternative design is to treat all parameters as keyword<br>
|arguments (as Evan said in <a href="/issues/5454">[ruby-core:40195]</a>).<br>
|<br>
| def create_point(x, y, color = "white", size = 1)<br>
| p [x, y, color, size]<br>
| end<br>
| create_point(color: "red", x: 2, y: 3)<br>
| #=> [2, 3, "red", 1]</p>
<p>It's Python way, and I won't take it.</p>
<pre><code> matz.
</code></pre> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215092011-10-24T14:53:11Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>Hi,</p>
<p>In message "Re: <a href="https://blade.ruby-lang.org/ruby-core/40299">[ruby-core:40299]</a> Re: [ruby-trunk - Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/5474">#5474</a>][Assigned] keyword argument"<br>
on Mon, 24 Oct 2011 14:12:21 +0900, Evan Phoenix <a href="mailto:evan@phx.io" class="email">evan@phx.io</a> writes:</p>
<p>|> | def create_point(x, y, color = "white", size = 1)<br>
|> | p [x, y, color, size]<br>
|> | end<br>
|> | create_point(color: "red", x: 2, y: 3)<br>
|> | #=> [2, 3, "red", 1]<br>
|><br>
|> It's Python way, and I won't take it.<br>
|What don't you like about this approach? I'd like to know so that hopefully I can formulate an alternative you would like.<br>
|<br>
|My worry about Yusuke's current proposal is that it requires a Hash be allocated on the caller side to use the feature, which makes the usage of keyword arguments much more heavyweight than normal arguments. This in turn means people will either shy away from them or use them and complain that they're too slow (which could make ruby look bad).<br>
|<br>
| - Evan</p>
<p>It could make argument parsing much heavyweight and difficult to<br>
predict, both user POV and implementation POV. The Python argument<br>
rules are very complex comparing to other parts of the language.</p>
<p>Besides that, as Yusuke mentioned, I think the current proposal still<br>
have much room to optimize, e.g. deferring hash allocation until<br>
really needed.</p>
<pre><code> matz.
</code></pre> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215412011-10-25T23:23:11Zheadius (Charles Nutter)headius@headius.com
<ul></ul><p>On Mon, Oct 24, 2011 at 12:12 AM, Evan Phoenix <a href="mailto:evan@phx.io" class="email">evan@phx.io</a> wrote:</p>
<blockquote>
<blockquote>
<p>|An alternative design is to treat all parameters as keyword<br>
|arguments (as Evan said in <a href="/issues/5454">[ruby-core:40195]</a>).<br>
|<br>
| def create_point(x, y, color = "white", size = 1)<br>
| p [x, y, color, size]<br>
| end<br>
| create_point(color: "red", x: 2, y: 3)<br>
| #=> [2, 3, "red", 1]</p>
<p>It's Python way, and I won't take it.<br>
What don't you like about this approach? I'd like to know so that hopefully I can formulate an alternative you would like.</p>
</blockquote>
</blockquote>
<p>The overhead concerns may not be valid. I think it could be<br>
implemented such that the overhead would only be there if called with<br>
a keyword parameter form. Otherwise, all arguments are treated<br>
positionally.</p>
<p>Quick pseudo-algorithm:</p>
<p>call_args = #<br>
if args.kind_of? Hash<br>
newargs = []<br>
position_map = method.keyword_to_position<br>
call_args.each do |key, value|<br>
case key<br>
when String<br>
newargs[position_map[key]] = value<br>
when Fixnum<br>
newargs[key] = value<br>
end<br>
end<br>
call_args = newargs<br>
end<br>
method.call_with_args call_args</p>
<p>This would be detectable at compile time; only methods that have<br>
keyword args would do the additional logic of mapping names to<br>
positions.</p>
<p>However, this way of optimizing it does require keyword args always<br>
come after regular positional args. I think that's not too big a leap<br>
to make, since they have to be at the end right now. It does not<br>
require they be specified by the caller in the same order as the<br>
target method, as in MacRuby.</p>
<p>There is a problem with this proposal, though: it could easily break<br>
current code that uses "hash args". For example, a legacy case:</p>
<p>def foo(who, hash)<br>
...<br>
end</p>
<p>foo('hello', who: 'world')</p>
<p>This example is slightly contrived, but under current Rubies the "who"<br>
variable in the "foo" method would get 'hello', and under Evan's<br>
proposal it would be 'world'. For this reason I think explicitly<br>
notating keyword parameters in the argument list is better.</p>
<blockquote>
<p>My worry about Yusuke's current proposal is that it requires a Hash be allocated on the caller side to use the feature, which makes the usage of keyword arguments much more heavyweight than normal arguments. This in turn means people will either shy away from them or use them and complain that they're too slow (which could make ruby look bad).</p>
</blockquote>
<p>I think the cost of constructing a Hash in Rubinius may be coloring<br>
your thoughts here...and I don't blame you; even though Hash<br>
construction in JRuby is pretty fast, it's not free:</p>
<p><a href="https://gist.github.com/1312815" class="external">https://gist.github.com/1312815</a></p>
<p>However, I think much of the Hash-borne overhead could be blunted by<br>
having keyword arg hashes be frozen and list-based. Most of the time<br>
there's no more than a handful of keyword args in use, so having them<br>
be "Hash-like" but backed by a simple associative array would make<br>
them considerably cheaper to construct in all implementations:</p>
<p><a href="https://gist.github.com/a07c93c80dfdea023253" class="external">https://gist.github.com/a07c93c80dfdea023253</a></p>
<p>In any case, I don't think there's any reason Yusuke's version would<br>
<em>require</em> they be a hash unless the target method <em>needs</em> them to be a<br>
hash. More pseudocode:</p>
<p>AT CALL SITE:</p>
<p>call_args = # ...<br>
if call_args.kind_of? Hash</p>
<a name="map-to-positional-args-internally"></a>
<h1 >map to positional args internally<a href="#map-to-positional-args-internally" class="wiki-anchor">¶</a></h1>
<p>end<br>
...</p>
<p>IN METHOD PREAMBLE:</p>
<p>if self.keyword_args?<br>
if self.keyword_rest?<br>
# unpack positional keyword args with "rest" hash<br>
else<br>
# unpack (or not) positional to keyword offsets<br>
end<br>
end</p>
<p>You'd only pay for the hash if you want it.</p>
<ul>
<li>Charlie</li>
</ul> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215592011-10-26T08:23:12ZAnonymous
<ul></ul><p>See below.</p>
<p>--<br>
Evan Phoenix // <a href="mailto:evan@phx.io" class="email">evan@phx.io</a></p>
<blockquote>
<blockquote>
<p>My worry about Yusuke's current proposal is that it requires a Hash be allocated on the caller side to use the feature, which makes the usage of keyword arguments much more heavyweight than normal arguments. This in turn means people will either shy away from them or use them and complain that they're too slow (which could make ruby look bad).</p>
</blockquote>
<p>I think the cost of constructing a Hash in Rubinius may be coloring<br>
your thoughts here...and I don't blame you;<br>
It might be, but when you compare calling a method with normal arguments to creating a Hash, it doesn't matter what runtime your in, the difference is huge.</p>
<p><a href="https://gist.github.com/a07c93c80dfdea023253" class="external">https://gist.github.com/a07c93c80dfdea023253</a></p>
<p>In any case, I don't think there's any reason Yusuke's version would<br>
<em>require</em> they be a hash unless the target method <em>needs</em> them to be a<br>
hash.<br>
Ok, good. This is actually all that I ask. As it's being designed, take into account a way to implement it without having to allocate a full every time. If this consideration is given in the design phase, I'm sure we'll all make it work efficiently.</p>
</blockquote>
<ul>
<li>Evan</li>
</ul> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215722011-10-27T07:23:09Zjballanc (Joshua Ballanco)jballanc@gmail.com
<ul></ul><p>On Wed, Oct 26, 2011 at 2:08 PM, Yukihiro Matsumoto <a href="mailto:matz@ruby-lang.org" class="email">matz@ruby-lang.org</a>wrote:</p>
<blockquote>
<p>Hi,</p>
<p>In message "Re: <a href="https://blade.ruby-lang.org/ruby-core/40414">[ruby-core:40414]</a> Re: [ruby-trunk - Feature<br>
<a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/5474">#5474</a>][Assigned] keyword argument"<br>
on Thu, 27 Oct 2011 02:51:51 +0900, Charles Oliver Nutter <<br>
<a href="mailto:headius@headius.com" class="email">headius@headius.com</a>> writes:</p>
<p>|Evan and I would like to see support for non-default keyword args. So<br>
|the following form would require that "size" be provided as a keyword<br>
|arg, and otherwise raise an ArgumentError:<br>
|<br>
|def create_point(x, y, color: "white", size:)</p>
<p>I don't know the reason why you need this value-less keyword<br>
argument. If you want the default value, you just need to omit the<br>
keyword altogether.</p>
</blockquote>
<p>I think the point is that not every argument necessarily has a reasonable<br>
default. Imagine, for example, if we were to rewrite File.open to take<br>
keyword arguments:</p>
<pre><code> class File
def self.open(filename:, mode: 'r')
...
</code></pre>
<p>It would be desirable to call such a method as <code>File.open(filename: "foo.txt")</code> but omitting the "filename:" argument should be an error.<br>
Perhaps, if a hash-like syntax is desired, we could introduce a "required"<br>
keyword:</p>
<pre><code> class File
def self.open(filename: required, mode: 'r')
...
</code></pre>
<p>such that omitting the option raises an ArgumentError?</p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215742011-10-27T07:53:12Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>Hi,</p>
<p>In message "Re: <a href="https://blade.ruby-lang.org/ruby-core/40414">[ruby-core:40414]</a> Re: [ruby-trunk - Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/5474">#5474</a>][Assigned] keyword argument"<br>
on Thu, 27 Oct 2011 02:51:51 +0900, Charles Oliver Nutter <a href="mailto:headius@headius.com" class="email">headius@headius.com</a> writes:</p>
<p>|Evan and I would like to see support for non-default keyword args. So<br>
|the following form would require that "size" be provided as a keyword<br>
|arg, and otherwise raise an ArgumentError:<br>
|<br>
|def create_point(x, y, color: "white", size:)</p>
<p>I don't know the reason why you need this value-less keyword<br>
argument. If you want the default value, you just need to omit the<br>
keyword altogether.</p>
<p>Besides that, what is the value corresponding to size: keyword above?<br>
Even though keyword argument implementation can bypass the hash<br>
allocation as optimization, we still have to keep hash semantics, I think.</p>
<pre><code> matz.
</code></pre> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215762011-10-27T09:53:17Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>Hi,</p>
<p>In message "Re: <a href="/issues/5474">[ruby-core:40418]</a> Re: [ruby-trunk - Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/5474">#5474</a>][Assigned] keyword argument"<br>
on Thu, 27 Oct 2011 04:03:52 +0900, Joshua Ballanco <a href="mailto:jballanc@gmail.com" class="email">jballanc@gmail.com</a> writes:</p>
<p>|I think the point is that not every argument necessarily has a reasonable<br>
|default. Imagine, for example, if we were to rewrite File.open to take<br>
|keyword arguments:<br>
|<br>
| class File<br>
| def self.open(filename:, mode: 'r')<br>
| ...</p>
<p>Yes, there could be a language with that kind of design. But Ruby<br>
will not have mandatory keyword arguments. It is the design choice I<br>
made already. Every keyword argument will be optional in Ruby.</p>
<pre><code> matz.
</code></pre> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215792011-10-27T10:23:29Zjballanc (Joshua Ballanco)jballanc@gmail.com
<ul></ul><p>On Wed, Oct 26, 2011 at 8:30 PM, Yukihiro Matsumoto <a href="mailto:matz@ruby-lang.org" class="email">matz@ruby-lang.org</a>wrote:</p>
<blockquote>
<p>Hi,</p>
<p>In message "Re: <a href="/issues/5474">[ruby-core:40418]</a> Re: [ruby-trunk - Feature<br>
<a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/5474">#5474</a>][Assigned] keyword argument"<br>
on Thu, 27 Oct 2011 04:03:52 +0900, Joshua Ballanco <<br>
<a href="mailto:jballanc@gmail.com" class="email">jballanc@gmail.com</a>> writes:</p>
<p>|I think the point is that not every argument necessarily has a reasonable<br>
|default. Imagine, for example, if we were to rewrite File.open to take<br>
|keyword arguments:<br>
|<br>
| class File<br>
| def self.open(filename:, mode: 'r')<br>
| ...</p>
<p>Yes, there could be a language with that kind of design. But Ruby<br>
will not have mandatory keyword arguments. It is the design choice I<br>
made already. Every keyword argument will be optional in Ruby.</p>
</blockquote>
<p>Thank you for the clarification. I am slowly understanding the direction and<br>
motivation behind the keyword arguments feature.</p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215802011-10-27T11:23:09Zheadius (Charles Nutter)headius@headius.com
<ul></ul><p>On Wed, Oct 26, 2011 at 7:30 PM, Yukihiro Matsumoto <a href="mailto:matz@ruby-lang.org" class="email">matz@ruby-lang.org</a> wrote:</p>
<blockquote>
<p>Yes, there could be a language with that kind of design. But Ruby<br>
will not have mandatory keyword arguments. It is the design choice I<br>
made already. Every keyword argument will be optional in Ruby.</p>
</blockquote>
<p>Can you clarify why you've already made this decision? For normal<br>
positional arguments, there are required args, optional args, and rest<br>
args. It seems like having the same types of arguments for keyword<br>
args would be more consistent.</p>
<p>Also, Evan pointed out to me that if Ruby doesn't support mandatory<br>
keyword arguments, you're going to see a <em>lot</em> of this pattern:</p>
<p>def foo(a: nil)<br>
raise ArgumentError, 'must pass value for a' unless a<br>
..<br>
end</p>
<p>So in essence, by making all keyword arguments optional, you're<br>
forcing users to do their own required argument checks. Is that going<br>
to make programmers happy?</p>
<ul>
<li>Charlie</li>
</ul> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215912011-10-27T18:29:10Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<ul></ul><p>Hi,</p>
<p>(11/10/27 11:02), Charles Oliver Nutter wrote:</p>
<blockquote>
<p>Also, Evan pointed out to me that if Ruby doesn't support mandatory<br>
keyword arguments, you're going to see a <em>lot</em> of this pattern:</p>
<p>def foo(a: nil)<br>
raise ArgumentError, 'must pass value for a' unless a<br>
..<br>
end</p>
</blockquote>
<p>It should be a positinal argument. I can't get why it must be a<br>
keyword argument.</p>
<blockquote>
<p>So in essence, by making all keyword arguments optional, you're<br>
forcing users to do their own required argument checks. Is that going<br>
to make programmers happy?</p>
</blockquote>
<p>An alternative:<br>
def foo(a: raise(ArgumentError))<br>
end</p>
<p>--<br>
Nobu Nakada</p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215922011-10-27T18:59:12Zheadius (Charles Nutter)headius@headius.com
<ul></ul><p>On Thu, Oct 27, 2011 at 3:16 AM, Nobuyoshi Nakada <a href="mailto:nobu@ruby-lang.org" class="email">nobu@ruby-lang.org</a> wrote:</p>
<blockquote>
<p>(11/10/27 11:02), Charles Oliver Nutter wrote:</p>
<blockquote>
<p>def foo(a: nil)<br>
raise ArgumentError, 'must pass value for a' unless a<br>
..<br>
end</p>
</blockquote>
<p>It should be a positinal argument. I can't get why it must be a<br>
keyword argument.</p>
</blockquote>
<p>It's a contrived example, of course, but I think having a neat<br>
parallel between positional args (required, optional, rest) and<br>
keyword args (required, optional, rest) would serve users well.</p>
<p>Honestly, I'm not one to argue for increased complexity in argument<br>
processing...the 1.9 support for array destructuring still gives me<br>
nightmares. But in this case, it seems like having keyword args mirror<br>
positional args is a good idea.</p>
<blockquote>
<blockquote>
<p>So in essence, by making all keyword arguments optional, you're<br>
forcing users to do their own required argument checks. Is that going<br>
to make programmers happy?</p>
</blockquote>
<p>An alternative:<br>
def foo(a: raise(ArgumentError))<br>
end</p>
</blockquote>
<p>You are an evil, evil man. :)</p>
<ul>
<li>Charlie</li>
</ul> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215932011-10-27T23:23:28Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>Hi,</p>
<p>In message "Re: <a href="/issues/5474">[ruby-core:40449]</a> Re: [ruby-trunk - Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/5474">#5474</a>][Assigned] keyword argument"<br>
on Thu, 27 Oct 2011 18:56:51 +0900, Charles Oliver Nutter <a href="mailto:headius@headius.com" class="email">headius@headius.com</a> writes:</p>
<p>|It's a contrived example, of course, but I think having a neat<br>
|parallel between positional args (required, optional, rest) and<br>
|keyword args (required, optional, rest) would serve users well.</p>
<p>I disagree here. Unlike other languages, keyword arguments will be<br>
labels to optional arguments in Ruby. This decision comes after the<br>
deep consideration for long time. I don't think I am going to change<br>
my mind here.</p>
<p>|Honestly, I'm not one to argue for increased complexity in argument<br>
|processing...the 1.9 support for array destructuring still gives me<br>
|nightmares. But in this case, it seems like having keyword args mirror<br>
|positional args is a good idea.</p>
<p>How contradicting humans are.</p>
<pre><code> matz.
</code></pre> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215942011-10-28T00:23:16Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul></ul><p>Hello,</p>
<p>2011/10/27 Yukihiro Matsumoto <a href="mailto:matz@ruby-lang.org" class="email">matz@ruby-lang.org</a>:</p>
<blockquote>
<p>Yes, there could be a language with that kind of design. But Ruby<br>
will not have mandatory keyword arguments. It is the design choice I<br>
made already. Every keyword argument will be optional in Ruby.</p>
</blockquote>
<p>I like the design.</p>
<p>I hate to write File.open(filename: "foo") . Just redundant.<br>
I don't want such a style to be popularized.</p>
<p>BTW, a current optional parameter will be deprecated?<br>
I don't like the feature because it is not extensible.<br>
Actually, I hate to see ERB.new(src, nil, "%") anymore!<br>
It now just complicates the language.</p>
<p>Of course I don't think it will be removed in 2.0.<br>
Let it be just deprecated now, and remove it in further future,<br>
such as 3.0. What do you think?</p>
<p>--<br>
Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a></p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215952011-10-28T00:53:24Znow (Nikolai Weibull)now@disu.se
<ul></ul><p>On Thu, Oct 27, 2011 at 17:16, Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a> wrote:</p>
<blockquote>
<p>2011/10/27 Yukihiro Matsumoto <a href="mailto:matz@ruby-lang.org" class="email">matz@ruby-lang.org</a>:</p>
<blockquote>
<p>Yes, there could be a language with that kind of design. But Ruby<br>
will not have mandatory keyword arguments. It is the design choice I<br>
made already. Every keyword argument will be optional in Ruby.</p>
</blockquote>
</blockquote>
<blockquote>
<p>BTW, a current optional parameter will be deprecated?<br>
I don't like the feature because it is not extensible.<br>
Actually, I hate to see ERB.new(src, nil, "%") anymore!<br>
It now just complicates the language.</p>
</blockquote>
<p>Agree! This would clean up both the language and the implementation<br>
and make for better APIs.</p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215962011-10-28T00:59:22Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>Hi,</p>
<p>In message "Re: <a href="/issues/5474">[ruby-core:40454]</a> Re: [ruby-trunk - Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/5474">#5474</a>][Assigned] keyword argument"<br>
on Fri, 28 Oct 2011 00:16:33 +0900, Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a> writes:</p>
<p>|BTW, a current optional parameter will be deprecated?<br>
|I don't like the feature because it is not extensible.<br>
|Actually, I hate to see ERB.new(src, nil, "%") anymore!<br>
|It now just complicates the language.<br>
|<br>
|Of course I don't think it will be removed in 2.0.<br>
|Let it be just deprecated now, and remove it in further future,<br>
|such as 3.0. What do you think?</p>
<p>Removing something, especially well-used feature like (non-labeled)<br>
optional arguments is a big thing. We have to consider it very<br>
carefully. I'd say there's possibility, for now.</p>
<pre><code> matz.
</code></pre> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215972011-10-28T01:53:21Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<ul></ul><p>Hi,</p>
<p>(11/10/27 18:56), Charles Oliver Nutter wrote:</p>
<blockquote>
<p>On Thu, Oct 27, 2011 at 3:16 AM, Nobuyoshi Nakada <a href="mailto:nobu@ruby-lang.org" class="email">nobu@ruby-lang.org</a> wrote:</p>
<blockquote>
<p>An alternative:<br>
def foo(a: raise(ArgumentError))<br>
end</p>
</blockquote>
<p>You are an evil, evil man. :)</p>
</blockquote>
<p>You didn't know? ;)</p>
<p>Anyway, isn't it better to show which default value was evaluated in<br>
the backtrace?</p>
<p>--<br>
Nobu Nakada</p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=215982011-10-28T02:59:15Zheadius (Charles Nutter)headius@headius.com
<ul></ul><p>On Thu, Oct 27, 2011 at 11:42 AM, Nobuyoshi Nakada <a href="mailto:nobu@ruby-lang.org" class="email">nobu@ruby-lang.org</a> wrote:</p>
<blockquote>
<p>You didn't know? ;)</p>
<p>Anyway, isn't it better to show which default value was evaluated in<br>
the backtrace?</p>
</blockquote>
<p>Yes, it definitely is. I would like to see Ruby do that for me, but<br>
since it sounds like it won't...</p>
<p>this seems too long, and that's with a very short message:</p>
<p>def foo(a: raise(ArgumentError, 'missing a')))</p>
<p>I think this is better but ugly:</p>
<p>def foo(a: nil)<br>
raise ArgumentError, 'missing a' if a.nil?</p>
<p>The other problem with the second version is that nil might be a valid<br>
value to pass in for a. So if Ruby doesn't enforce required keyword<br>
args, you actually have to use this pattern:</p>
<p>def foo(a: (no_a = true; nil))<br>
raise ArgumentError, 'missing a' if no_a</p>
<p>Bleah.</p>
<ul>
<li>Charlie</li>
</ul> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=216472011-10-30T08:23:07ZEregon (Benoit Daloze)
<ul></ul><p>Hi,</p>
<p>On 23 October 2011 14:53, Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a> wrote:</p>
<blockquote>
<p>Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/5474">#5474</a>: keyword argument</p>
</blockquote>
<p>It sounds great!</p>
<p>I agree mandatory keyword arguments should be positional arguments and<br>
all parameters should not be treated as keyword arguments.</p>
<p>I have a few questions/remarks:</p>
<ol>
<li>What is the way to pass keyword arguments ?<br>
I would guess <code>**h</code> like:</li>
</ol>
<p>def meth(a, **h)<br>
other(a, **h)<br>
end # => syntax error</p>
<p>BTW, using **h in the argument list does not seems to work in some cases for me:</p>
<p>def a(**h)<br>
end # => syntax error, unexpected tPOW</p>
<p>def m(k: nil, **h, &block)<br>
end<br>
m() # => undefined method `key?' for nil:NilClass</p>
<ol start="2">
<li>I'm a bit dubious about the <code>**h</code> syntax to get (and I guess to pass) a Hash though.<br>
I know it's the way it's done in Python, but I don't like it (esthetically),<br>
especially when it is used to pass the Hash:</li>
</ol>
<p>def meth(a, *r, **h)<br>
other(a, *r, **h)<br>
end</p>
<p>I believe <code>*args</code> is appropriate for the rest argument, because the star is the splat operator.<br>
I cannot think of any clear logic like that for <code>**h</code> except "another rest argument".<br>
Also <code>**</code> is the power operator, which is unrelated.<br>
Something related to <code>{}</code>, the literal Hash syntax, would fit better in my opinion.</p>
<p>Do you have any idea of an alternate syntax to <code>**h</code> ?</p>
<p>(Or maybe we should introduce <code>a, b = **h</code> as a joke for <code>a, b = h.values_at(:a, :b)</code>)</p>
<ol start="3">
<li>What would {Proc,Method,UnboundMethod}#parameters returns for keywords arguments ?</li>
</ol>
<p>def meth(mandatory, optional = nil, *rest, post, keyw: nil, **h, &block)<br>
end<br>
p method(:meth).parameters<br>
Currently: [[:req, :mandatory], [:opt, :optional], [:rest, :rest], [:req, :post], [:block, :block]]<br>
Something like:<br>
[[:req, :mandatory], [:opt, :optional], [:rest, :rest], [:req, :post], [:key, :keyw], [:keyrest, :h], [:block, :block]] ?</p>
<ol start="4">
<li>I noticed a few problems while experimenting:<br>
def a(k: :a, **h)<br>
p [k,h]<br>
end<br>
a(:b, c: :d, e: :f) # => wrong number of arguments (2 for 0) (ArgumentError)<br>
It should be "1 for 0"</li>
</ol>
<p>def a(k: :a)<br>
p [k,h]<br>
end<br>
a(r: :a) # => unknown keyword (TypeError)<br>
It should say which keyword is missing (and an ArgumentError rather than TypeError, no?).</p>
<p>(Of course I do not expect the current patch to pass these details,<br>
I just mention them to be sure they will be considered.)</p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=216702011-10-31T07:53:07ZEregon (Benoit Daloze)
<ul></ul><p>On 30 October 2011 11:10, Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a> wrote:</p>
<blockquote>
<p>Hello,</p>
<p>Koichi told me that I can commit my patch to the trunk. So<br>
I'll do after I fix the issues Benoit reported.<br>
But I'll remain this ticket open to continue to discuss the<br>
spec.</p>
<p>2011/10/30 Benoit Daloze <a href="mailto:eregontp@gmail.com" class="email">eregontp@gmail.com</a>:</p>
<blockquote>
<p>I have a few questions/remarks:</p>
</blockquote>
<p>Thank you very much for your trying my patch and your opinion!</p>
</blockquote>
<p>It's all my pleasure to test shiny new features.</p>
<blockquote>
<blockquote>
<ol>
<li>What is the way to pass keyword arguments ?<br>
I would guess <code>**h</code> like:</li>
</ol>
<p>def meth(a, **h)<br>
other(a, **h)<br>
end # => syntax error</p>
</blockquote>
<p>I didn't implement caller's **.<br>
I wonder if we need it or not. Is "other(a, h)" not enough?</p>
</blockquote>
<p>I don't know why I thought keyword arguments were a separate type of<br>
arguments, while there are mostly syntactic sugar for treating the<br>
Hash given, if I understand well (which is fine, except maybe for<br>
optimizations from the implementer POV, but I don't know well).</p>
<p>In that case, it is indeed enough.</p>
<blockquote>
<blockquote>
<p>BTW, using **h in the argument list does not seems to work in some cases for me:</p>
<p>def a(**h)<br>
end # => syntax error, unexpected tPOW</p>
</blockquote>
<p>Currently, my patch allows ** only when there are one or more<br>
keyword arguments.</p>
<p>This is because I didn't think of any use case.<br>
In addition, I wanted to simplify the implementation of parser.<br>
(Unfortunately, adding a new argument type requries <em>doubling</em><br>
the parser rules to avoid yacc's conflict)<br>
Do you think we need it?</p>
</blockquote>
<p>No, sorry for the confusion.<br>
(Ugh, doubling the parser rules sounds bad)</p>
<blockquote>
<blockquote>
<p>def m(k: nil, **h, &block)<br>
end<br>
m() # => undefined method `key?' for nil:NilClass</p>
</blockquote>
<p>This must be a bug. I'll fix it. Thanks!</p>
</blockquote>
<p>It seems to happen only when there is the &block parameter in my experience.</p>
<blockquote>
<blockquote>
<ol start="2">
<li>I'm a bit dubious about the <code>**h</code> syntax to get (and I guess to<br>
pass) a Hash though.</li>
</ol>
</blockquote>
<p>As I said above, it serves as just <code>get', not </code>pass,' currently.</p>
<blockquote>
<p>I believe <code>*args</code> is appropriate for the rest argument, because the<br>
star is the splat operator.<br>
I cannot think of any clear logic like that for <code>**h</code> except "another<br>
rest argument".<br>
Also <code>**</code> is the power operator, which is unrelated.<br>
Something related to <code>{}</code>, the literal Hash syntax, would fit better<br>
in my opinion.</p>
</blockquote>
<p>I accept another syntax, if it is allowed by matz, and yacc :-)</p>
<blockquote>
<p>Do you have any idea of an alternate syntax to <code>**h</code> ?</p>
</blockquote>
<p>No I don't.</p>
</blockquote>
<p>Given the above considerations, <code>**h</code> will only be used to get the<br>
Hash, so I think it is fine.<br>
Notably, delegating with method missing will stay simple as it is:</p>
<p>def method_missing(*args, &block)<br>
other(*args, &block)<br>
end</p>
<blockquote>
<blockquote>
<ol start="3">
<li>What would {Proc,Method,UnboundMethod}#parameters returns for<br>
keywords arguments ?</li>
</ol>
</blockquote>
<p>Indeed. I completely forgot. I'll do.</p>
</blockquote>
<p>I would happily write the tests for that if you want.<br>
Do you agree on the :key and :keyrest (now I'm thinking to :hash) names ?</p>
<blockquote>
<blockquote>
<ol start="4">
<li>I noticed a few problems while experimenting:<br>
def a(k: :a, **h)<br>
p [k,h]<br>
end<br>
a(:b, c: :d, e: :f) # => wrong number of arguments (2 for 0) (ArgumentError)<br>
It should be "1 for 0"</li>
</ol>
</blockquote>
<p>Yes, the error message should be considered.<br>
But in the case, you're passing two arguments actually:<br>
":b", and "{:c=>:d, :e=>:f}"<br>
Do you mean the keyword argument (= hash) should be ignored?</p>
</blockquote>
<ul>
<li>Show quoted text -</li>
</ul>
<blockquote>
<blockquote>
<p>def a(k: :a)<br>
p [k,h]<br>
end<br>
a(r: :a) # => unknown keyword (TypeError)<br>
It should say which keyword is missing</p>
</blockquote>
<p>Strongly agreed. I was just lazy :-)</p>
</blockquote>
<p>The first virtue of a programmer :-)</p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=217992011-11-02T02:23:16ZAnonymous
<ul></ul><blockquote>
<blockquote>
<p>An alternative design is to treat all parameters as keyword<br>
arguments (as Evan said in <a href="/issues/5454">[ruby-core:40195]</a>).</p>
<p>Â def create_point(x, y, color</p>
</blockquote>
</blockquote> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=218242011-11-03T00:53:13ZAnonymous
<ul></ul><blockquote>
<p>|> It's Python way, and I won't take it.<br>
|What don't you like about this approach? I'd like to know so that hopefully I can formulate an alternative you would like.<br>
|<br>
|My worry about Yusuke's current proposal is that it requires a Hash be allocated on the caller side to use the feature, which makes the usage of keyword arguments much more heavyweight than normal arguments. This in turn means people will either shy away from them or use them and complain that they're too slow (which could make ruby look bad).<br>
|<br>
| - Evan</p>
<p>It could make argument parsing much heavyweight and difficult to<br>
predict, both user POV and implementation POV. Â The Python argument<br>
rules are very complex comparing to other parts of the language.</p>
</blockquote>
<p>So your concern is that it would become too complicated if positional<br>
parameters were also treated as keyword, is that right?</p>
<p>My concern with that is then "how do you specify a non optional<br>
parameter by keyword?" (unless you accept Charles' proposal).<br>
Thank you.<br>
-roger-</p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=229112011-12-22T05:33:54Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><p>While having fun testing your patch, I encountered an issue with more than 2 rest arguments:</p>
<pre><code>def foo(*rest, b: 0, **options)
[rest, options]
end
foo(1, 2, bar: 0) # => [[1, 2], {bar: 0}] OK
foo(1, 2, 3, bar: 0) # => [[1, 2, {bar: 0}], {bar: 0}] Not OK
</code></pre> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=229122011-12-22T06:46:25Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><p>On 30 October 2011 11:10, Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a> wrote:</p>
<blockquote>
<p>Currently, my patch allows ** only when there are one or more<br>
keyword arguments.</p>
<p>This is because I didn't think of any use case.<br>
In addition, I wanted to simplify the implementation of parser.<br>
(Unfortunately, adding a new argument type requries <em>doubling</em><br>
the parser rules to avoid yacc's conflict)<br>
Do you think we need it?</p>
</blockquote>
<p>I'm worried about cases where one doesn't use named arguments directly but wants to pass them on to another method.</p>
<p>Let's say we have a Gem that defines:</p>
<p>def import(*files, format: :auto_detect, encoding: "utf-8")<br>
# ...<br>
end</p>
<p>Say one wants to implement a variation of this that prints out a progression. If it was possible to have a ** arg, one could:</p>
<p>def my_import(*files, **options)<br>
puts "Importing #{files.size} files: #{files}"<br>
import(*files, options)<br>
end</p>
<p>A new version of the gem can modify the method <code>import</code> by adding options, or changing the default of any option, add options and <code>my_import</code> would work perfectly.</p>
<p>But if we can't define it this way, we have to do some artificial hoop jumping. Either:</p>
<p>def my_import(*files, format: :auto_detect, encoding: "utf-8")<br>
puts "Importing #{files.size} files: #{files}..."<br>
import(*files, format: format, encoding: encoding)# ...<br>
end</p>
<p>Downsides: verbose, won't pass on any new options, default changes won't be reflected</p>
<p>def my_import(*files, format: :auto_detect, **options)<br>
puts "Importing #{files.size} files: #{files}"<br>
import(*files, options.merge(format: format))# ...<br>
end</p>
<p>Downsides: verbose, format looks like a special option and if its default changes in the Gem, it won't be reflected, but others will</p>
<p>def my_import(*args)<br>
files = args.dup<br>
files.pop if files.last.respond_to?(:to_hash)<br>
puts "Importing #{files.size} files: #{files}"<br>
import(*args)<br>
end</p>
<p>Downside: <code>*args</code> less clear then <code>*files, **options</code>, slower, verbose, ...</p>
<p>I feel that the first (currently illegal) version is the much nicer than the alternatives.</p>
<blockquote>
<p>I didn't implement caller's **.<br>
I wonder if we need it or not. Is "other(a, h)" not enough?</p>
</blockquote>
<p>I think one reason to have it is to avoid calling Hash#merge when combining options, like in the above examples.</p>
<p>Instead of</p>
<pre><code>def foo(bar: 42, **options)
baz(extra_option: 1, **options)
end
</code></pre>
<p>Currently, one has to do:</p>
<pre><code>def foo(bar: 42, **options)
baz(options.merge(extra_option: 1))
end
</code></pre>
<p>Benoit Daloze wrote:</p>
<blockquote>
<ol start="2">
<li>I'm a bit dubious about the <code>**h</code> syntax to get (and I guess to pass) a Hash though.<br>
...<br>
Something related to <code>{}</code>, the literal Hash syntax, would fit better in my opinion.</li>
</ol>
<p>Do you have any idea of an alternate syntax to <code>**h</code> ?</p>
</blockquote>
<p>I haven't given much thought, but here's an alternate suggestion, where **h => {*h}:</p>
<pre><code>def foo(a, b=1, *rest, {c: 2, d: 3, *options})
end
</code></pre>
<p>If the parser allows, the {} could be optional, at least in the case without a "hash-rest" argument.</p>
<p>This could actually be two new concepts that could be used everywhere in Ruby (not just for argument passing):<br>
a) Splat inside a hash does a merge, e.g.</p>
<pre><code>h = {foo: 1, bar: 2}
{*h, baz: 3} # => {foo: 1, bar: 2, baz: 3}
</code></pre>
<p>I'm not sure if it should be silent in case of duplicate key (like <code>Hash#merge</code> with no block) or if it should raise an error.</p>
<p>b) Hash destructuring, e.g.:</p>
<pre><code>h = {foo: 1, bar: 2}
{foo: 42, extra: 0, *rest} = h
foo # => 1
extra # => 0
rest # => {bar: 2}
</code></pre>
<p>It would be nice to not need a default:</p>
<pre><code>{foo, extra, *rest} = h
extra # => nil
</code></pre>
<p>This could be allowed in arguments too:</p>
<pre><code>def foo(a, b=1, *rest, {c, d, *options})
end
</code></pre>
<p>What do you think?</p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=229142011-12-22T07:05:03Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul><li><strong>Target version</strong> set to <i>2.0.0</i></li></ul> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=229222011-12-22T13:59:08ZAnonymous
<ul></ul><p>Hi,</p>
<p>Not sure why the following modifications made in redmine were not<br>
posted on the mailing list...</p>
<p>While having fun testing your patch, I encountered an issue with more<br>
than 2 rest arguments:</p>
<pre><code> def foo(*rest, b: 0, **options)
[rest, options]
end
foo(1, 2, bar: 0) # => [[1, 2], {bar: 0}] OK
foo(1, 2, 3, bar: 0) # => [[1, 2, {bar: 0}], {bar: 0}] Not OK
</code></pre>
<p>On 30 October 2011 11:10, Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a> wrote:</p>
<blockquote>
<p>Currently, my patch allows ** only when there are one or more<br>
keyword arguments.</p>
<p>This is because I didn't think of any use case.<br>
In addition, I wanted to simplify the implementation of parser.<br>
(Unfortunately, adding a new argument type requries <em>doubling</em><br>
the parser rules to avoid yacc's conflict)<br>
Do you think we need it?</p>
</blockquote>
<p>I'm worried about cases where one doesn't use named arguments directly<br>
but wants to pass them on to another method.</p>
<p>Let's say we have a Gem that defines:</p>
<p>def import(*files, format: :auto_detect, encoding: "utf-8")<br>
# ...<br>
end</p>
<p>Say one wants to implement a variation of this that prints out a<br>
progression. If it was possible to have a ** arg, one could:</p>
<p>def my_import(*files, **options)<br>
puts "Importing #{files.size} files: #{files}"<br>
import(*files, options)<br>
end</p>
<p>A new version of the gem can modify the method <code>import</code> by adding<br>
options, or changing the default of any option, add options and<br>
<code>my_import</code> would work perfectly.</p>
<p>But if we can't define it this way, we have to do some artificial hoop<br>
jumping. Either:</p>
<p>def my_import(*files, format: :auto_detect, encoding: "utf-8")<br>
puts "Importing #{files.size} files: #{files}..."<br>
import(*files, format: format, encoding: encoding)# ...<br>
end</p>
<p>Downsides: verbose, won't pass on any new options, default changes<br>
won't be reflected</p>
<p>def my_import(*files, format: :auto_detect, **options)<br>
puts "Importing #{files.size} files: #{files}"<br>
import(*files, options.merge(format: format))# ...<br>
end</p>
<p>Downsides: verbose, format looks like a special option and if its<br>
default changes in the Gem, it won't be reflected, but others will</p>
<p>def my_import(*args)<br>
files = args.dup<br>
files.pop if files.last.respond_to?(:to_hash)<br>
puts "Importing #{files.size} files: #{files}"<br>
import(*args)<br>
end</p>
<p>Downside: <code>*args</code> less clear then <code>*files, **options</code>, slower, verbose, ...</p>
<p>I feel that the first (currently illegal) version is the much nicer<br>
than the alternatives.</p>
<blockquote>
<p>I didn't implement caller's **.<br>
I wonder if we need it or not. Is "other(a, h)" not enough?</p>
</blockquote>
<p>I think one reason to have it is to avoid calling Hash#merge when<br>
combining options, like in the above examples.</p>
<p>Instead of</p>
<pre><code> def foo(bar: 42, **options)
baz(extra_option: 1, **options)
end
</code></pre>
<p>Currently, one has to do:</p>
<pre><code> def foo(bar: 42, **options)
baz(options.merge(extra_option: 1))
end
</code></pre>
<p>Benoit Daloze wrote:</p>
<blockquote>
<ol start="2">
<li>I'm a bit dubious about the <code>**h</code> syntax to get (and I guess to pass) a Hash though.<br>
...<br>
Something related to <code>{}</code>, the literal Hash syntax, would fit better in my opinion.</li>
</ol>
<p>Do you have any idea of an alternate syntax to <code>**h</code> ?</p>
</blockquote>
<p>I haven't given much thought, but here's an alternate suggestion,<br>
where **h => {*h}:</p>
<pre><code> def foo(a, b=1, *rest, {c: 2, d: 3, *options})
end
</code></pre>
<p>If the parser allows, the {} could be optional, at least in the case<br>
without a "hash-rest" argument.</p>
<p>This could actually be two new concepts that could be used everywhere<br>
in Ruby (not just for argument passing):<br>
a) Splat inside a hash does a merge, e.g.</p>
<pre><code> h = {foo: 1, bar: 2}
{*h, baz: 3} # => {foo: 1, bar: 2, baz: 3}
</code></pre>
<p>I'm not sure if it should be silent in case of duplicate key (like<br>
<code>Hash#merge</code> with no block) or if it should raise an error.</p>
<p>b) Hash destructuring, e.g.:</p>
<pre><code> h = {foo: 1, bar: 2}
{foo: 42, extra: 0, *rest} = h
foo # => 1
extra # => 0
rest # => {bar: 2}
</code></pre>
<p>It would be nice to not need a default:</p>
<pre><code> {foo, extra, *rest} = h
extra # => nil
</code></pre>
<p>This could be allowed in arguments too:</p>
<pre><code> def foo(a, b=1, *rest, {c, d, *options})
end
</code></pre>
<p>What do you think?</p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=229652011-12-26T23:27:03Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul><li><strong>Assignee</strong> changed from <i>ko1 (Koichi Sasada)</i> to <i>mame (Yusuke Endoh)</i></li></ul><p>Hello,</p>
<p>I've committed my patches for keyword arguments, with fixes for<br>
some problems reported during this discussion.<br>
Please try it and let me know if you find any problem.</p>
<p>This feature still requires discussion, so I'm leaving this<br>
ticket open.</p>
<p>--<br>
Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a></p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=229662011-12-26T23:29:10Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul></ul><p>Hello, Marc-Andre</p>
<p>2011/12/22, Marc-Andre Lafortune <a href="mailto:ruby-core-mailing-list@marc-andre.ca" class="email">ruby-core-mailing-list@marc-andre.ca</a>:</p>
<blockquote>
<p>While having fun testing your patch, I encountered an issue with more<br>
than 2 rest arguments:</p>
<pre><code>def foo(*rest, b: 0, **options)
[rest, options]
end
foo(1, 2, bar: 0) # => [[1, 2], {bar: 0}] OK
foo(1, 2, 3, bar: 0) # => [[1, 2, {bar: 0}], {bar: 0}] Not OK
</code></pre>
</blockquote>
<p>Good catch! The commits I've done now include a fix for this.</p>
<blockquote>
<p>On 30 October 2011 11:10, Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a> wrote:</p>
<blockquote>
<p>Currently, my patch allows ** only when there are one or more<br>
keyword arguments.</p>
<p>This is because I didn't think of any use case.<br>
In addition, I wanted to simplify the implementation of parser.<br>
(Unfortunately, adding a new argument type requries <em>doubling</em><br>
the parser rules to avoid yacc's conflict)<br>
Do you think we need it?</p>
</blockquote>
<p>I'm worried about cases where one doesn't use named arguments directly<br>
but wants to pass them on to another method.</p>
</blockquote>
<p>Indeed. I've missed delegate.</p>
<blockquote>
<blockquote>
<p>I didn't implement caller's **.<br>
I wonder if we need it or not. Is "other(a, h)" not enough?</p>
</blockquote>
<p>I think one reason to have it is to avoid calling Hash#merge when<br>
combining options, like in the above examples.</p>
<p>Instead of</p>
<pre><code>def foo(bar: 42, **options)
baz(extra_option: 1, **options)
end
</code></pre>
<p>Currently, one has to do:</p>
<pre><code>def foo(bar: 42, **options)
baz(options.merge(extra_option: 1))
end
</code></pre>
</blockquote>
<p>Oh yeah, I understand the use case.</p>
<p>I'll work for these two, after matz shows his opinion for<br>
your new alternative syntax. Thanks!</p>
<p>--<br>
Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a></p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=229672011-12-26T23:53:26Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul></ul><p>Hello, Matz</p>
<p>What do you think about Marc-Andre's alternative syntax for<br>
keyword arguments and mechanism?</p>
<p>2011/12/22, Marc-Andre Lafortune <a href="mailto:ruby-core-mailing-list@marc-andre.ca" class="email">ruby-core-mailing-list@marc-andre.ca</a>:</p>
<blockquote>
<p>I haven't given much thought, but here's an alternate suggestion,<br>
where **h => {*h}:</p>
<p>def foo(a, b=1, *rest, {c: 2, d: 3, *options})<br>
end</p>
<p>If the parser allows, the {} could be optional, at least in the case<br>
without a "hash-rest" argument.</p>
<p>This could actually be two new concepts that could be used everywhere<br>
in Ruby (not just for argument passing):<br>
a) Splat inside a hash does a merge, e.g.</p>
<pre><code>h = {foo: 1, bar: 2}
{*h, baz: 3} # => {foo: 1, bar: 2, baz: 3}
</code></pre>
<p>I'm not sure if it should be silent in case of duplicate key (like<br>
<code>Hash#merge</code> with no block) or if it should raise an error.</p>
<p>b) Hash destructuring, e.g.:</p>
<pre><code>h = {foo: 1, bar: 2}
{foo: 42, extra: 0, *rest} = h
foo # => 1
extra # => 0
rest # => {bar: 2}
</code></pre>
<p>It would be nice to not need a default:</p>
<pre><code>{foo, extra, *rest} = h
extra # => nil
</code></pre>
<p>This could be allowed in arguments too:</p>
<pre><code>def foo(a, b=1, *rest, {c, d, *options})
end
</code></pre>
</blockquote>
<p>I think the mechanism looks neater then my proposal.<br>
My first proposal is less flexible; it allows us only keyword<br>
arguments by making the complex concept, i.e., method arguments,<br>
more complex.</p>
<p>On the contrary, Marc-Andre's proposal consists of some small<br>
concepts (each which looks useful) and minimum extension for<br>
method arguments. It is agreement with the Unix philosophy ---<br>
do one thing and do it well.</p>
<p>I'm not sure if his proposal is implementable or not, but if you<br>
prefer it, I (or anyone) will try to implement it.</p>
<p>Which do you prefer?</p>
<p>--<br>
Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a></p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=229692011-12-27T06:59:34Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>Hi,</p>
<p>In message "Re: <a href="/issues/5474">[ruby-core:41814]</a> Re: [ruby-trunk - Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/5474">#5474</a>][Assigned] keyword argument"<br>
on Mon, 26 Dec 2011 23:28:36 +0900, Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a> writes:</p>
<p>|Oh yeah, I understand the use case.<br>
|<br>
|I'll work for these two, after matz shows his opinion for<br>
|your new alternative syntax. Thanks!</p>
<p>I agree with caller-side **.</p>
<pre><code> matz.
</code></pre> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=229742011-12-27T12:53:14Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul></ul><p>Hello, matz</p>
<p>2011/12/27, Yukihiro Matsumoto <a href="mailto:matz@ruby-lang.org" class="email">matz@ruby-lang.org</a>:</p>
<blockquote>
<p>In message "Re: <a href="/issues/5474">[ruby-core:41814]</a> Re: [ruby-trunk - Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/5474">#5474</a>][Assigned]<br>
keyword argument"<br>
on Mon, 26 Dec 2011 23:28:36 +0900, Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a><br>
writes:</p>
<p>|Oh yeah, I understand the use case.<br>
|<br>
|I'll work for these two, after matz shows his opinion for<br>
|your new alternative syntax. Thanks!</p>
<p>I agree with caller-side **.</p>
</blockquote>
<p>Ah, yes, I think there is no longer need for arguing it.<br>
What I'm waiting for is your opinion not about it, but<br>
about <a href="/issues/5474">[ruby-core:41815]</a>.</p>
<p>--<br>
Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a></p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=229752011-12-27T15:53:07Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>Hi,</p>
<p>In message "Re: <a href="/issues/5474">[ruby-core:41815]</a> Re: [ruby-trunk - Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: keyword argument (Closed)" href="https://bugs.ruby-lang.org/issues/5474">#5474</a>][Assigned] keyword argument"<br>
on Mon, 26 Dec 2011 23:36:38 +0900, Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a> writes:<br>
|<br>
|Hello, Matz<br>
|<br>
|What do you think about Marc-Andre's alternative syntax for<br>
|keyword arguments and mechanism?</p>
<p>I am still not sure if we need hash splat nor hash decomposition, it<br>
might be useful in some cases, but also makes syntax more complex.<br>
So we need more discussion before picking it.</p>
<p>But if we could made consensus I'd make small changes to proposed<br>
syntax.</p>
<p>For hash splat, I'd rather use ** instead of *, because splat in array<br>
and splat in hash are different. Using same operator could cause<br>
confusion. Besides that, I would also restrict hash splat position to<br>
the end, since hashes do not have order.</p>
<pre><code> matz.
</code></pre> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=232292012-01-10T22:17:57Zyeban (Anurag Priyam)anurag08priyam@gmail.com
<ul></ul><p>Once this proposal has been implemented, would we also want to change the relevant API calls (in core, stdlib, etc.) to use keyword arguments instead of an optional Hash?</p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=261632012-04-24T22:01:35Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul><li><strong>Status</strong> changed from <i>Assigned</i> to <i>Closed</i></li></ul><p>Sorry for leaving this ticket for a long time.</p>
<p>Nobu improved the implementation of keyword argument.<br>
Let's check the current situation.<br>
And then, I'd like to file tickets for each remaining issues, and<br>
close this ticket. Please let me know if I miss something.</p>
<a name="-with-no-keyword-ruby-core40518-ruby-core41772"></a>
<h2 >** with no keyword <a href="/issues/5474">[ruby-core:40518]</a> <a href="/issues/5474">[ruby-core:41772]</a><a href="#-with-no-keyword-ruby-core40518-ruby-core41772" class="wiki-anchor">¶</a></h2>
<p>The following DOES work currently. Thanks nobu!</p>
<p>def foo(x, **h)<br>
p [x, h]<br>
end<br>
foo(1) #=> [1, {}]<br>
foo(1, key: 42) #=> [1, {key: 42}]<br>
foo(1, 2) #=> wrong number of arguments (2 for 1)</p>
<a name="Methodparameters-with-keyword-argument-ruby-core40518"></a>
<h2 >Method#parameters with keyword argument <a href="/issues/5474">[ruby-core:40518]</a><a href="#Methodparameters-with-keyword-argument-ruby-core40518" class="wiki-anchor">¶</a></h2>
<p>The following DOES work currently.</p>
<p>def foo(k1: 42, k2: 42, **kr)<br>
end<br>
p method(:foo).parameters<br>
#=> [[:key, :k1], [:key, :k2], [:keyrest, :kr]]</p>
<a name="caller-side-ruby-core40518"></a>
<h2 >caller-side ** <a href="/issues/5474">[ruby-core:40518]</a><a href="#caller-side-ruby-core40518" class="wiki-anchor">¶</a></h2>
<p>The following does NOT work.</p>
<p>h = {x: 42}<br>
foo(**h)</p>
<p>Unfortunately, it is not trivial for me to implement.<br>
I'll explain the detail in a separate ticket.</p>
<a name="alternative-syntax-proposal"></a>
<h2 >alternative syntax proposal<a href="#alternative-syntax-proposal" class="wiki-anchor">¶</a></h2>
<p>As far as I know, there is no proposal that matz approved.<br>
It looks difficult to me to change the syntax, because matz seems to<br>
like "**" very much. <a href="/issues/5474">[ruby-core:41822]</a></p>
<a name="Marc-Andres-hash-decomposition-ruby-core41772"></a>
<h2 >Marc-Andre's hash decomposition <a href="/issues/5474">[ruby-core:41772]</a><a href="#Marc-Andres-hash-decomposition-ruby-core41772" class="wiki-anchor">¶</a></h2>
<p>Unfortunately, matz is not so positive. <a href="/issues/5474">[ruby-core:41822]</a></p>
<a name="ArgumentError-message-related-to-keyword-argument"></a>
<h2 >ArgumentError message related to keyword argument<a href="#ArgumentError-message-related-to-keyword-argument" class="wiki-anchor">¶</a></h2>
<p>Currently, "unknown keyword" error shows which keyword is missing:</p>
<p>def a(k: 42)<br>
end<br>
a(foo: 42)<br>
# => unknown keyword: foo (ArgumentError)</p>
<p>There is another proposal about "wrong number of arguments" error.<br>
See: <a href="http://bugs.ruby-lang.org/issues/6086" class="external">http://bugs.ruby-lang.org/issues/6086</a></p>
<a name="changing-stdlib-API-to-use-keyword-arguments-ruby-core42037"></a>
<h2 >changing stdlib API to use keyword arguments <a href="/issues/5474">[ruby-core:42037]</a><a href="#changing-stdlib-API-to-use-keyword-arguments-ruby-core42037" class="wiki-anchor">¶</a></h2>
<p>I think we should progress it, without breaking compatibility.<br>
But currently, I don't know which API is the target.<br>
Please file a ticket if you find such an API.</p>
<p>--<br>
Yusuke Endoh <a href="mailto:mame@tsg.ne.jp" class="email">mame@tsg.ne.jp</a></p> Ruby master - Feature #5474: keyword argumenthttps://bugs.ruby-lang.org/issues/5474?journal_id=265402012-05-09T03:46:41Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><p>Hi,</p>
<p>mame (Yusuke Endoh) wrote:</p>
<blockquote>
<a name="Marc-Andres-hash-decomposition-ruby-core41772"></a>
<h2 >Marc-Andre's hash decomposition <a href="/issues/5474">[ruby-core:41772]</a><a href="#Marc-Andres-hash-decomposition-ruby-core41772" class="wiki-anchor">¶</a></h2>
<p>Unfortunately, matz is not so positive. <a href="/issues/5474">[ruby-core:41822]</a></p>
</blockquote>
<p>Maybe I misread Matz' comment, but I understood he was not sure yet.</p>
<p>In any case, a new feature request (<a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Destructuring Assignment (Closed)" href="https://bugs.ruby-lang.org/issues/6414">#6414</a>) was just opened, so we can discuss there.</p>