Hi,
On 23 October 2011 14:53, Yusuke Endoh <mame / tsg.ne.jp> wrote:
>
> Issue #5474 has been reported by Yusuke Endoh.
>
> ----------------------------------------
> Feature #5474: keyword argument
> http://redmine.ruby-lang.org/issues/5474
>
> Author: Yusuke Endoh
> Status: Assigned
> Priority: Normal
> Assignee: Koichi Sasada
> Category: core
> Target version:
>
>
> Hello,
>
> I'm sending a patch for keyword arguments.
>
> (This feature had been discussed in #5454, but I'm re-creating
> =A0a new ticket because the old ticket was resigtered in ruby-dev)
>
>
> Matz himself proposed this feature. =A0It is also basically
> promised to include the feature in 2.0. =A0[ruby-core:39837]
> I'm planning to commit the patch after it is reviewed by koichi.
>
> But the detail of the spec is not fixed yet, and may be changed
> drastically.
> We would like to hear your comments and suggestions, especially,
> with a use case and/or an actual experience.
>
>
>
> The background of this proposal is that, in the recent Ruby,
> the last argument (as a Hash) is often used to pass optional
> information. =A0This feature is intended to aid the style.
>
> Look an example:
>
> =A0 =A0def create_point(x, y, color: "white", size: 1)
> =A0 =A0 =A0# keyword arguments =A0^^^^^^^^^^^^^^^^^^^^^^^ here!
>
> =A0 =A0 =A0p [x, y, color, size]
> =A0 =A0end
>
> =A0 =A0create_point(2, 3, color: "red")
> =A0 =A0 =A0#=3D> [2, 3, "red", 1]
>
> The caller size is a traditional hash argument notation.
> This feature is Hash parsing in the callee side.
>
> (So it is more suitable to call it "keyword parameter."
> =A0But I use "keyword argument" because everyone calls so.)
>
>
> We can implement the similar behavior in pure Ruby. =A0However,
> this feature is easier to read/write, and richer in the some
> aspects:
>
> - it raises an TypeError when unknown keyword is given
>
> =A0 =A0create_point(2, 3, style: "solid")
> =A0 =A0 =A0#=3D> unknown keyword (TypeError)
>
> - you can use ** argument to suppress the TypeError and/or
> =A0to get the given hash itself:
>
> =A0 =A0def create_point(x, y, color: "white", size: 1, **h)
> =A0 =A0 =A0p [x, y, color, size, h]
> =A0 =A0end
> =A0 =A0create_point(2, 3, style: "solid")
> =A0 =A0 =A0#=3D> [2, 3, "red", 1, {:style=3D>"solid"}]
>
> - it is easily used even when there is a rest argument
>
> =A0 =A0def create_point(x, y, *r, color: "solid", size: 1)
> =A0 =A0 =A0...
> =A0 =A0end
>
> =A0(a complex and non-essential code is required to
> =A0 implement the same behavior in pure Ruby)
>
> - there is room for optimizing the speed (though I have
> =A0not done any optimization yet)
>
>
>
> An alternative design is to treat all parameters as keyword
> arguments (as Evan said in [ruby-core:40195]).
>
> =A0def create_point(x, y, color =3D "white", size =3D 1)
> =A0 =A0p [x, y, color, size]
> =A0end
> =A0create_point(color: "red", x: 2, y: 3)
> =A0 =A0#=3D> [2, 3, "red", 1]
>
> Actually I also like this, but I'm afraid if it is too flexible
> and seems difficult to implement and optimize.
>
>
> Thanks,
>
> --
> Yusuke Endoh <mame / tsg.ne.jp>
>
>
> --
> http://redmine.ruby-lang.org
>
>

It sounds great!

I agree mandatory keyword arguments should be positional arguments and
  all parameters should not be treated as keyword arguments.

I have a few questions/remarks:
1) What is the way to pass keyword arguments ?
I would guess `**h` like:

def meth(a, **h)
  other(a, **h)
end # =3D> syntax error

BTW, using **h in the argument list does not seems to work in some cases fo=
r me:

def a(**h)
end # =3D> syntax error, unexpected tPOW

def m(k: nil, **h, &block)
end
m() # =3D> undefined method `key?' for nil:NilClass

2) I'm a bit dubious about the `**h` syntax to get (and I guess to
pass) a Hash though.
I know it's the way it's done in Python, but I don't like it
(esthetically), especially when it is used to pass the Hash:

def meth(a, *r, **h)
  other(a, *r, **h)
end

I believe `*args` is appropriate for the rest argument, because the
star is the splat operator.
I cannot think of any clear logic like that for `**h` except "another
rest argument".
Also `**` is the power operator, which is unrelated.
Something related to `{}`, the literal Hash syntax, would fit better
in my opinion.

Do you have any idea of an alternate syntax to `**h` ?

(Or maybe we should introduce `a, b =3D **h` as a joke for `a, b =3D
h.values_at(:a, :b)`)

3) What would {Proc,Method,UnboundMethod}#parameters returns for
keywords arguments ?

def meth(mandatory, optional =3D nil, *rest, post, keyw: nil, **h, &block)
end
p method(:meth).parameters
Currently: [[:req, :mandatory], [:opt, :optional], [:rest, :rest],
[:req, :post], [:block, :block]]
Something like:
[[:req, :mandatory], [:opt, :optional], [:rest, :rest], [:req, :post],
[:key, :keyw], [:keyrest, :h], [:block, :block]] ?

4)  I noticed a few problems while experimenting:
def a(k: :a, **h)
  p [k,h]
end
a(:b, c: :d, e: :f) # =3D> wrong number of arguments (2 for 0) (ArgumentErr=
or)
It should be "1 for 0"

def a(k: :a)
  p [k,h]
end
a(r: :a) # =3D> unknown keyword (TypeError)
It should say which keyword is missing (and an ArgumentError rather
than TypeError, no?).

(Of course I do not expect the current patch to pass these details, I
just mention them to be sure they will be considered.)