--- Yukihiro Matsumoto <matz / ruby-lang.org> wrote:

> Hi,
> 
> In message "Re: A comparison by example of keyword argument
> styles"
>     on Mon, 24 Oct 2005 05:50:39 +0900, Eric Mahurin
> <eric_mahurin / yahoo.com> writes:
> 
> |What use is it to have the named arguments appear twice?  I
> |understand the need if you don't have named arguments in the
> |definition (compatibility), but as soon as named arguments
> are
> |specified, it seems to serve no purpose.
> 
> It's for method delegation.  Currently we do 
> 
>   def foo(*args)
>     bar(*args)
>   end
> 
> for method delegation.

To do the full delegation right now you really need:

def foo(*args, &block)
  bar(*args, &block)
end

> Under my proposal, this delegation
> would still
> work fine, since we have named arguments appear twice,
> otherwise we
> must change the code as
> 
>   def foo(*args, **keys)
>     bar(*args, **keys)
>   end
> 
> everywhere, to just do delegation.

or rather:

def foo(*args, **keys, &block)
  bar(*args, **keys, &block)
end

What's wrong with having to do that?  The old delegation would
be able to delegate to any of the old non-named argument method
definitions.  Existing code would not break.  Only when you
start using new named arguments in your method definitions
would you have to fix the delegation methods.

I think you need to choose whether you want separation between
named and positional arguments (like lisp and command-line
options/args) or not (like python/sydney).  And go with it. 
Having named arguments appear in the positional *args does not
show good separation - what you want I think.

> |Also, like we have array splatting when you call a method, I
> |think hash splatting would also be useful.  matz said that
> |hashes would be automatically splatted if they were the last
> |argument, but this results in ambiguity:
> |
> |def foo(a,b={},c:2,**keys) ... end
> |
> |foo("a",{:x => 1,:y => 2})
> |
> |Does the above result in:
> |
> |a = "a", b = {:x => 1,:y => 2}, c = 2, keys = {}
> |
> |or:
> |
> |a = "a", b = {}, c = 2, keys = {:x => 1,:y => 2}
> 
> The former.  Keyword argument uses the last remaining hash.

This contradicts what you said above about method delegation. 
If we had this delegation with the above foo:

def bar(*args)
  foo(*args)
end

bar("a", x: 1, y: 2)
# bar: args = ["a",{:x => 1, :y => 2}]
# foo: a = "a", b = {:x => 1,:y => 2}, c = 2, keys = {}

That's not what you wanted for delegating.  It should be:

foo: a = "a", b = {}, c = 2, keys = {:x => 1,:y => 2}

But then if you choose that, you have no way of passing a hash
to the last positional argument and giving no named arguments
(assuming they all have defaults).

I think with named arguments you should not give special
meaning to Hash or you'll run into the same problems you had
with multiple-value returns and assignments that you had with
Array.  Explicitly splatting/unsplatting a Hash for named
arguments makes sense, but I don't think you should tie Hash as
part of the definition of named arguments.

> |I'm hoping that we have enough reflection for these named
> |arguments like #arity.  I'm thinking that with named
> arguments 
> |a potential simple application would be as a spec for
> handling
> |command-line options (named arguments).  I'd like to see all
> of
> |the keywords and defaults accessible from Proc/Method
> objects. 
> |It'd be nice to have access to defaults of positional args
> |while wer'e asking.
> 
> Accepting keywords should be obtained from some kind of
> reflection
> API, although the API is not fixed yet.  But I'm not sure
> default
> values can be accessed since they are arbitrary expression,
> and we
> have no good way to represent pre-evaluated expression in
> Ruby (unlike
> in Lisp, where we can use S expression).

Sorry, I forgot that defaults can be expressions.  I guess you
could have something that just says whether an arg (positional
or named) has a default or not.  Another option is to be able
to access the default as a Proc.  To evaluate the default,
you'd just #call it like any other Proc.

> |Since Ruby 2 will also be completely redoing how
> |multiple-values are handled, why not also consider being
> able
> |to name your return values?  If a method returns a bunch of
> |attributes, it would be nice for the caller to be able to
> pick
> |what they want.
> 
> I have no good idea of multiple value binding for named
> values
> (i.e. syntax).  Do you?
> 
> 							matz.

Actually, I do.  If you put the ability to handle named
arguments in a multi-assign, you'll have it.  The LHS would
look like argument definitions in a def (except defaults aren't
allowed) and the RHS (or return) would look like a method call.
 The problem is that this will force the named argument to be
put in a variable of the same name when assigning to the LHS. 
To fix this problem, I propose that you be allowed to specify a
different local variable name for a named argument in a method
definition or LHS:

def foo(
  a,      # position: 0, local var: a, required
  b="b",  # position: 1, local var: b, default: "b"
  *args,  # position: 2..-1, local var: args 
  w:,     # name: w, local var: w, required
  x:c,    # name: x, local var: c, required
  y:="y", # name: y, local var: y, default: "y"
  z:d="z",# name: z, local var: d, default: "z"
  **keys) # name: others, local var: keys
....
  # maybe w: could be made equivalent to w:w
  return a,b,*args,w:w,x:c,y:y,z:d,**keys
end

# only care about pos:0 and name:x - throw out the rest
aa,x:xx = foo(0,1,2,w:3,x:4,m:5)

Like you allow discarded positional args ("_"), you could also
allow discarded named args (name:_[=default]).  And "**" like
"*" could mean accept any other keys but throw them out.

BTW, I'd still like to see the ability to specify required
positional args after the *args and/or default positional args.
 I see no reason why any of this named argument stuff would
conflict with this (RCR 315).



		
__________________________________ 
Yahoo! FareChase: Search multiple travel sites in one click.
http://farechase.yahoo.com