A comparison by example of keyword argument styles

Hi --

···

On Sat, 22 Oct 2005, Daniel Schierbeck wrote:

Damphyr wrote:

The :a syntax looks a lot like symbols ...

Erm, the keywords *are* symbols.

def foo(a: 1, b: 2, **keys)
   puts keys[:a] # :a is a symbol!
end

Therefore i think it's more clear if we write the keys as symbols.

def foo(:a = 1, :b = 2, **keys)
   puts keys[:a] # foo(:a) -> keys[:a]
end

:a = 1 parses visually like assignment to a symbol, and therefore
looks bizarre.

David

--
David A. Black
dblack@wobblini.net

Yukihiro Matsumoto wrote:

It's for method delegation. Currently we do

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

for method delegation. 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.

This is sinking worse and worse into a stenchy quagmire. If someone
puts **keys in the parameters then it makes sense for the keys NOT to
appear in args. I know you want to remain backward compatable so
without **keys then the keys will appear in args. But how does one say
they want any number of ordered parameters but NO named parameters? I
suppose you just can't. Moreover the args won't be cleanly separated.
So this doesn't do us much good, I'll still be pop'n off trailing
hashes :frowning: Really, think about that!

···

---

Thinking about reusing named parameters vs. adding key arguments
(better?) I recant on my previous statement of their being little
difference. The later does have one clear disadvantage: it requires a
choice --which parameters will be fixed and which will be keyed. Since
you can't have it both ways, it's really going to tie you down.
Consider this scenario:

You have a method already

  def foo(a,b=1,c=2)

Now it's been a bother b/c you want to sometimes call it as foo(a,c).
But you can't. To get around, you've done what we've all done at one
point or another, created an extra method

  def foo2(a,c=2,b=1)

Now along comes matz' keyd args. Does it help? Can you deprecate foo2
which you never really wanted in the first place and use?

  def foo(a,b:1,c:2)

You can but, ugh, that's serious backward compatabilty breakage!!! So
what to do? Do you add YAM (yet another method) #foo3 for this? Do you
get tricky with it and do

  def foo(a,b=1,c=2,b2:1,c2:2)
    b = b || b2
    c = c || c2

Well a little better, but now you have TWO DIFFERENT names for each
parameter and you could have just as well done this with a trailing
hash. The keyed args didn't buy you much of anything. Nope, it just
doesn't do us much good.

Buy let's say instead, here comes along the named parameters approach
like Sydney's. What happens? Easy peasy. Deprecate #foo2 (add a
warning) and your done. You can start using #foo in the new way
'foo(a,c:x)' as it suits you and backward compatability is maintained.

---

In anycase case one of the nice things about named args, should you
with to change a parameter name, you can offer both during a transition
period, in fact you may want to offer a few alternatives anyway to make
usage a bit more fluid.

  def foo( beer:, beers:, beer_bottles: )
    b = beer || beers || beer_bottles

A way to specify an OR in the signiture would be nice with something
like this too. Say:

  def foo( beer: | beers: | beer_bottles: )
    b = beer # doesn't matter which.

But again the problem that starts to arise here are _very large
signitures_. And again to me this indicatates a real need for some type
of Signture class one can use to define them and plug them in where
needed, even reuse them. Such an object would give ultimate reflexion
too.

---

Just some comparisions:

  foo(:foo=>:do, :bar=>:re, :baz=>:mi) # today

  foo(foo=>:do, bar=>:re, baz=>:mi) # minor adj.

  foo(foo: :do, bar: :re, baz: :mi) # colon notation

  foo(foo:`do, bar:`re, baz:`mi) # alt. symbol

---

BTW, those of you who do get me --I'm not trying to make some major
coherent argument. I'm just pointing out various vantages.

T.

Hi,

>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).

···

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

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:

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

Trans wrote:

Because the keys *are* symbols, and they have colons in front of them.

But they're *not* symbols. They're local vars.

T.

   def foo(a:, **keys)
     puts keys[:a] # the key "a" is a symbol
   end

I'd agree if the named arguments worked like positional ones, ie

   def foo(a:)
     puts a
   end

But unless I've completely misunderstood what's been suggested here, that's not the case.

Cheers,
Daniel

Hi,

···

In message "Re: A comparison by example of keyword argument styles" on Sat, 22 Oct 2005 22:33:48 +0900, Yukihiro Matsumoto <matz@ruby-lang.org> writes:

Unlike Ruby,

I meant "unlike Python".

              matz.

Trans said:

foo (a=1) #=> 1

Yes, I am aware of that. But can you actually point to me some library
code that actually uses this as a feature? I have most definitively
never seen any ruby code using that as of yet, and even then, I would
say that variable assignment within an expression is just something to
win the obfuscated code award, not a useful functionality.

Matz mentioned:

Besides that, I don't think Python keyword arguments are simple and elegant, but YMMV.

Could you elaborate why you prefer the other syntax? I can give you my
reasons for strongly suggesting following python's syntax, instead of
what you proposed.

To me, python's approach is simpler because:
a) There is no need for re-definiing a lot of previously written code
with a new syntax. If you have already written a function like
      def x(a,b,c)
   with the python automatic naming syntax, it makes the code still
work both positionally (as before) and now as named parameters --
automatically. Using a new syntax like a: or whatever, forces you to
basically have to rewrite all previously written code to make it work
with named parameters. While certainly functions that have used hashes
to accomplish a similar approach will need to get updated (or those
that used non-sensical names for function parameters), there shouldn't
be the need to update all previously written functions that did not
suffer from this. By not using any new special symbols, you gain the
functionality in pretty much most already written functions -- all of
ruby library, for example. A big, big plus, in my opinion. For the
parser and interpreter, it does makes things harder, but that's more or
less as it should be -- complexity on the side of the interpreter, not
on the side of the user.

b) There is a symetry between default parameter values and passing new
values to parameters in functions. This makes the code easier to
comprehend and the language easier to learn. That is:
      def function(a, b = 2, c = 3):
          ...
      function( 1, b = 4, c = 5)

      or (sans parenthesis)
      function b = 4, c = 5

     (Yes, I know that with the current use of = in ruby, the above
"function b = 4, c = 5" makes it impossible for the interpreter to
disambiguate, but assume dispatching of equality was not allowed within
functions -- as it isn't during a def definition, so that parsing the
above should be possible).

     Compared to (if I understood the proposal correctly):
      def function(a, b: = 2, c: = 3) # ugly
      end

      function( 1, b : 4, c : 5)
      function b: 4, c: 5 # use of : looks nicer, but
see also point c for issues

      In this proposed ruby syntax, colons are used as assignment in
one situation, while in another situation, it is equality that it is
used. Confusing.

c) ruby already uses the :x syntax to denote symbols and, in the
ruby1.9 head also for hash definitions with symbol keys. This presents
another big, big, big source of confusion.
There was already a mail in this thread that already showed the big
confusion this leads to, as someone used the symbol notation in the
function definition incorrectly. Also, compare the invokation issues:
       function to = :london, from = :paris
      to:
       function to: :london, from: :paris

    The first example can not lead to typos that the interpreter will
misinterpret.
    However, the second example can lead to two very easy to make
typos:
     function :to :london # oops, two symbols used, etc. probably
flagged as syntax error during parsing?
     function to::london # oops, this can NOT flagged as syntax
error, but leads to a runtime error only. Bad.

     True, with the appearance of named parameters, the use of symbols
in function invokations will probably be much less than what it is now,
but...

Anyway, my 2 cents on the issue.

it's not that big a deal to do is it? i've abstracted this in alib like so:

   harp:~ > cat a.rb
   require 'alib'
   include ALib::Util

   def meth *argv
     args, opts = optfilter argv
     foo = getopt 'foo', opts
     bar = getopt 'bar', opts, 'forty-two' # default value

     p 'args' => args
     p 'opts' => opts
     p 'foo' => foo
     p 'bar' => bar
   end

   meth 'foo', 'bar', 'foo' => 42

   harp:~ > ruby a.rb
   {"args"=>["foo", "bar"]}
   {"opts"=>{"foo"=>42}}
   {"foo"=>42}
   {"bar"=>"forty-two"}

easy cheasy. parseargs abstracts even further. if a language mod must be
made the answer seems clear: old style keywords land in *args as before, new
style ones land in keys, for example:

   def meth *args
     p args
   end

   meth 42 #=> [42]
   meth 42, 'foo' => 42 #=> [42, {'foo' => 42}]

   def meth *args, **keys
     p [args, keys]
   end

   meth 42 #=> [ [42], {} ]
   meth 42, 'foo' => 42 #=> [ [42, {'foo' => 42}], {} ]
   meth 42, foo : 42 #=> [ [42, {}], {'foo' => 42} ]
   meth 42, 'foo' => 42, foo : 42 #=> [ [42, {'foo' => 42}], {'foo' => 42} ]

i might add that i hope whatever keys object will hash key and symbol
arguments the same so we can do

   val = keys['foo']

or

   val = keys[:foo]

i hate having to check for both (that's what getopt above does).

2cts.

-a

···

On Mon, 24 Oct 2005, Trans wrote:

Yukihiro Matsumoto wrote:

It's for method delegation. Currently we do

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

for method delegation. 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.

This is sinking worse and worse into a stenchy quagmire. If someone puts
**keys in the parameters then it makes sense for the keys NOT to appear in
args. I know you want to remain backward compatable so without **keys then
the keys will appear in args. But how does one say they want any number of
ordered parameters but NO named parameters? I suppose you just can't.
Moreover the args won't be cleanly separated. So this doesn't do us much
good, I'll still be pop'n off trailing hashes :frowning: Really, think about that!

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
anything that contradicts experience and logic should be abandoned.
-- h.h. the 14th dalai lama

===============================================================================

Right, so this is probably a really dumb idea, but I was just having a
little bit of fun. It would be cool if you could define methods like this:

define :foo do
required :bar, :baz
optional :request => 'useless'
named :side,
:meat => 'fish'
body do
puts "Good, I got to say #{foo}#{bar}."
puts "You thought of my third request was #{request}"
puts "For dinner we have #{meat}"
if side
puts "With a side of #{side}"
end
end
end

foo 'hello ', 'world', :meat => 'steak', :side => 'potatoes'

That is the first few times you wrote a definition like that. Then it would
get very old very quickly I'm assuming :wink:

Hi,

···

In message "Re: A comparison by example of keyword argument styles" on Tue, 25 Oct 2005 00:15:35 +0900, Eric Mahurin <eric_mahurin@yahoo.com> writes:

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?

It's longer than it is really needed. I want to delegate everything
I've passed, that's all. I'd rather delegate blocks as well when I
write bar(*args).

              matz.

   def foo(a:)
     puts a
   end

Well, matz has given the reason

vgs% cmucl -quiet
* (defun foo (&key a) (list a))

FOO
* (foo :a 12)

(12)
* (quit)
vgs%

OK ?

Guy Decoux

   def foo(a:, **keys)
     puts keys[:a] # the key "a" is a symbol
   end

and to give you another example

vgs% cmucl -quiet
* (defun foo (&rest keys &key a &allow-other-keys)(list keys a))

FOO
* (foo :a 12)

((:A 12) 12)
* (foo :a 12 :b 24)

((:A 12 :B 24) 12)
* (quit)
vgs%

Guy Decoux

Could you elaborate why you prefer the other syntax? I can give you my
reasons for strongly suggesting following python's syntax, instead of
what you proposed.

Never mind me. I read David Black's response and I see the point.

Still, if the positional / named argument definition is chosen, could I
also suggest that a symbol (or keyword) is used to delimit positional
vs. named arguments, without having to specify it on each variable?

That is, instead of:

     def function( a, b, c, d:, e: = 1, f: )
     end

Something along the lines of:

   def function( a, b, c : d, e = 1, f )
   end

where parameters to the left of the colon (or whatever symbol/keyword
you choose) are positional parameters and those to the right are named
ones. A more readable symbol for this would be "!" or "|" but
obviously these conflict with ruby's use of those for negation/or.
This would somewhat help solve the issue of the definition being so
easily confused with symbols, make the function more readable (imo) and
would lead to less typing, too. If your model is CLISP, this is also
how CLISP deals with this (using &key), like:

    (defun foo ( &key a b c ) (list a b c))

Thanks... sorry for my 3 emails.

Ara.T.Howard wrote:

it's not that big a deal to do is it? i've abstracted this in alib like so:

   harp:~ > cat a.rb
   require 'alib'
   include ALib::Util

   def meth *argv
     args, opts = optfilter argv
     foo = getopt 'foo', opts
     bar = getopt 'bar', opts, 'forty-two' # default value

     p 'args' => args
     p 'opts' => opts
     p 'foo' => foo
     p 'bar' => bar
   end

   meth 'foo', 'bar', 'foo' => 42

   harp:~ > ruby a.rb
   {"args"=>["foo", "bar"]}
   {"opts"=>{"foo"=>42}}
   {"foo"=>42}
   {"bar"=>"forty-two"}

easy cheasy. parseargs abstracts even further.

That's nice, but then why would we need key args if we'd do this
anyway?

if a language mod must be
made the answer seems clear: old style keywords land in *args as before, new
style ones land in keys, for example:

   def meth *args
     p args
   end

   meth 42 #=> [42]
   meth 42, 'foo' => 42 #=> [42, {'foo' => 42}]

   def meth *args, **keys
     p [args, keys]
   end

   meth 42 #=> [ [42], {} ]
   meth 42, 'foo' => 42 #=> [ [42, {'foo' => 42}], {} ]
   meth 42, foo : 42 #=> [ [42, {}], {'foo' => 42} ]
   meth 42, 'foo' => 42, foo : 42 #=> [ [42, {'foo' => 42}], {'foo' => 42} ]

From what I understand this isn't what will happen, but rather

   meth 42, foo : 42 #=> [ [42, {:foo => 42}], {:foo => 42} ]

and

   meth 42, 'foo' => 42, foo : 42 #=> Error

i might add that i hope whatever keys object will hash key and symbol
arguments the same so we can do

   val = keys['foo']

or

   val = keys[:foo]

i hate having to check for both (that's what getopt above does).

Interesting point. Perhaps better then:

  val = keys.foo

Would go even better with Evan's mixed parameter object.

  def(*parms)
    p parms
    p parms.named
    p parms.foo
  end

  foo( 1,2,foo:3 )
  => [1,2]
     {:foo=>3}
     3

T.

Yukihiro Matsumoto wrote:

It's for method delegation. Currently we do

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

for method delegation. 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.

This is sinking worse and worse into a stenchy quagmire. If someone puts
**keys in the parameters then it makes sense for the keys NOT to appear
in
args. I know you want to remain backward compatable so without **keys
then
the keys will appear in args. But how does one say they want any number
of
ordered parameters but NO named parameters? I suppose you just can't.
Moreover the args won't be cleanly separated. So this doesn't do us
much
good, I'll still be pop'n off trailing hashes :frowning: Really, think about
that!

it's not that big a deal to do is it?

Yeah, but this just seems like fixing the symptoms of a problem
rather than the root cause. I have to say, the further this goes
on, the less I like the Lispish syntax for the sheer convolutedness.
Lisp did things the way it did because of its implementation an
possibly limitations ruby does not suffer from.

Also, and please enlighten me here, I have seen no tangible payback
for the added complexity except for being able to opt out of using
keyword arguments altoghether (Sydney's model creating them implicitly).
Am I missing something? I do not think there is any advantage in
delegation (when implemented as I posted earlier).

<snip example>

-a

E

···

On Mon, 24 Oct 2005, Trans wrote:

Widdle it:

def foo( required :bar, :baz ; optional :request=>'useless' ; named
:side, :meat=>'fish' )

def foo( bar, baz ; optional :request=>'useless' ; named :side,
:meat=>'fish' )

def foo( bar, baz, request='useless', keys: side, meat=>'fish' )

def foo( bar, baz, request='useless', side=>nil, meat=>'fish' )

T.

harp:~ > cat a.rb
   require 'parseargs'
   include ParseArgs

   def meth *argv
     pa =
       parseargs(argv) do
         req_arg 'foo', 'bar'
         opt_arg 'request' => 'useless'
         opt_kw 'side'
         opt_kw 'meat' => 'fish'
       end

     puts <<-txt
       Good, I got to say #{ pa.foo } #{ pa.bar }.
       You thought of my third request was #{ pa.request }
       For dinner we have #{ pa.meat }
     txt

     if pa.side
       puts "With a side of #{ pa.side }"
     end
   end

   meth 'hello ', 'world', 'useless', :meat => 'steak', :side => 'potatoes'

   harp:~ > ruby a.rb
       Good, I got to say hello world.
       You thought of my third request was useless
       For dinner we have steak
   With a side of potatoes

note. it's impossible to determine, if an argument is optional (your 'request'
above) if the last hash passed __is__ that optional argument itself or if it's
the set of keywords. therfore you must pass 'useless' for the request in this
case - if you think about it the parsing is otheriwse impossible.

cheers.

-a

···

On Tue, 25 Oct 2005, Louis J Scoras wrote:

Right, so this is probably a really dumb idea, but I was just having a
little bit of fun. It would be cool if you could define methods like this:

define :foo do
required :bar, :baz
optional :request => 'useless'
named :side,
:meat => 'fish'
body do
puts "Good, I got to say #{foo}#{bar}."
puts "You thought of my third request was #{request}"
puts "For dinner we have #{meat}"
if side
puts "With a side of #{side}"
end

foo 'hello ', 'world', :meat => 'steak', :side => 'potatoes'

That is the first few times you wrote a definition like that. Then it would
get very old very quickly I'm assuming :wink:

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
anything that contradicts experience and logic should be abandoned.
-- h.h. the 14th dalai lama

===============================================================================

Yukihiro Matsumoto ha scritto:

Hi,

>> 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?

It's longer than it is really needed. I want to delegate everything
I've passed, that's all. I'd rather delegate blocks as well when I
write bar(*args).

              matz.

sorry if this was already explained, how do I do if I don't want to delegate everything?

···

In message "Re: A comparison by example of keyword argument styles" > on Tue, 25 Oct 2005 00:15:35 +0900, Eric Mahurin <eric_mahurin@yahoo.com> writes:

amen! maybe bar(_).

-a

···

On Tue, 25 Oct 2005, Yukihiro Matsumoto wrote:

Hi,

In message "Re: A comparison by example of keyword argument styles" > on Tue, 25 Oct 2005 00:15:35 +0900, Eric Mahurin <eric_mahurin@yahoo.com> writes:

>> 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?

It's longer than it is really needed. I want to delegate everything
I've passed, that's all. I'd rather delegate blocks as well when I
write bar(*args).

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
anything that contradicts experience and logic should be abandoned.
-- h.h. the 14th dalai lama

===============================================================================

So would a Proc for the block appear as the last element of
args? If so, you'd have ambiguity between a Proc as the last
positional arg (with no block) and having a block. Or would
you have a special class for blocks? Either way you'd create
compatibility problems. Or maybe args wouldn't be a normal
Array and "hide" the block (and named args)? Splatting this
would reveal the block and/or named args when you delegate.

What if you want to pass on the positional args but give your
own block (or named arguments)?

If delegation is the only reason for wanting named-args (and
blocks) to appear in the positional args, what about having a
new syntax that splats/unsplats all types of arguments
(positional, named, block) into a special object? This object
would closely correlate to the method-call mechanism so that
minimal overhead is needed. Maybe *&:

def foo(*&args) # grab positional, named, and block
  bar(*&args) # pass positional, named, and block
end

The *& would have to be the last "argument" (positional, named,
block) given in the method definition and method call. Maybe
you would allow positional arguments to come before it - but no
other kind.

Matz, what did you think about the idea of being able to use
named arguments in a multi-assign so that you could return
named arguments? Like I said, I think the only thing that is
needed to make this reasonable is the ability to have the
keyword and the local variable name different. Then make make
the multi-LHS look similar to arguments in a method definition
and a multi-RHS/return look like arguments in a method call.

···

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

Hi,

In message "Re: A comparison by example of keyword argument > styles" > on Tue, 25 Oct 2005 00:15:35 +0900, Eric Mahurin > <eric_mahurin@yahoo.com> writes:

>> 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?

It's longer than it is really needed. I want to delegate
everything
I've passed, that's all. I'd rather delegate blocks as well
when I
write bar(*args).

              matz.

__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around

In article <1130222755.861386.32126.nullmailer@x31.priv.netlab.jp>,
  Yukihiro Matsumoto <matz@ruby-lang.org> writes:

>def foo(*args, **keys, &block)
> bar(*args, **keys, &block)
>end
>
>What's wrong with having to do that?

It's longer than it is really needed. I want to delegate everything
I've passed, that's all. I'd rather delegate blocks as well when I
write bar(*args).

I think an array, *args, is a structure too poor to
represent the all arguments.

How about **keys contains positional arguments and block?
A hash is enough rich to represent positional argument and
block addition to keyword arguments.

def foo(**keys)
  p keys
  bar(**keys)
end

foo(1, 2, k:3) {}

=> {:k => 3, "positional" => [1, 2], "block" => lambda {}}

This means keys contains special pairs for positional
arguments and block. In this example, "positional" and
"block" is used because strings are disjoint from symbols as
hash keys.

···

--
Tanaka Akira