Confusion Over Keyword Arguments

From: Yukihiro Matsumoto [mailto:matz@ruby-lang.org]
Sent: Wednesday, March 01, 2006 4:46 PM
To: ruby-talk ML
Subject: Re: Confusion Over Keyword Arguments

<snip>

>How about "=" for keyword arguments instead
>(such as in python)?

Unfortunately, assignments are legal in argument list in Ruby.

              matz.

That can be made to work, with the understanding that '=' in a method
call means 'keyword argument', not 'assignment', since there is no point
in doing an assignment in a method call.

# Method definition, '=' means assignment (of default value):
def foo(bar, baz = 3)
   ...
end

# Method call, '=' means keyword
foo(baz = 5, bar = 2)

For anyone who cares to read my past thoughts on the subject:

Regards,

Dan

···

-----Original Message-----

but is

   foo baz = 5, bar = 2

   a, b = foo(baz = 5), (bar = 2)

or

   a = foo( (baz = 5), (bar = 2) )

??

-a

···

On Fri, 3 Mar 2006, Berger, Daniel wrote:

-----Original Message-----
From: Yukihiro Matsumoto [mailto:matz@ruby-lang.org]
Sent: Wednesday, March 01, 2006 4:46 PM
To: ruby-talk ML
Subject: Re: Confusion Over Keyword Arguments

<snip>

>How about "=" for keyword arguments instead
>(such as in python)?

Unfortunately, assignments are legal in argument list in Ruby.

              matz.

That can be made to work, with the understanding that '=' in a method
call means 'keyword argument', not 'assignment', since there is no point
in doing an assignment in a method call.

# Method definition, '=' means assignment (of default value):
def foo(bar, baz = 3)
  ...
end

# Method call, '=' means keyword
foo(baz = 5, bar = 2)

--
judge your success by what you had to give up in order to get it.
- h.h. the 14th dali lama

You could use it to avoid repeating myself, for example in testing:

assert_instance_of(Name, (name = Name.new( (first = "James"), (last = "Gray") )))
assert_equal(first, name.first)
assert_equal(last, name.last)

James Edward Gray II

···

On Mar 2, 2006, at 9:57 AM, Berger, Daniel wrote:

That can be made to work, with the understanding that '=' in a method
call means 'keyword argument', not 'assignment', since there is no point
in doing an assignment in a method call.

Hi,

That can be made to work, with the understanding that '=' in a method
call means 'keyword argument', not 'assignment', since there is no point
in doing an assignment in a method call.

I'm not sure if we _can_. yacc is a tough guy to fight with.

Better Keyword Arguments - Testing 1,2,3... — LiveJournal

In this article, you've proposed *rest to slurp keyword hash. Indeed
it is simple, but maybe too simpler. I don't get how it can co-exist
with _your_ ideal keyword parameters. I.e. how the following code
should work?

def foo(a, b=0, *c)
    ...
end

foo(1, foo:3) # (a=1, b={:foo=>3}) or (a=1,b=0,c=[{:foo=>3}])?
foo(1, 2, 8, c:5) # c={:c=>5}) or c=[8,{:c=>5}] or error?
args = [1, {:b=>2, foo=>5}]
foo(*args) # (a=1,b={:b=>2, foo=>5}) or (a=1,b=2,c=[{:foo=>5}])?

              matz.

···

In message "Re: Confusion Over Keyword Arguments" on Fri, 3 Mar 2006 00:57:44 +0900, "Berger, Daniel" <Daniel.Berger@qwest.com> writes:

This has reference to the discussion in the article below.

> The Price of Explicitness - Testing 1,2,3... — LiveJournal

From the discussion on parameters to Array.new therein, I got the feeling that there were two distinct issues that somehow got mixed up:

(a) method signature -- how many arguments does it accept, which have defaults, etc., and

(b) which set of arguments belong to the same signature.

Just because of Array.new has a form that accepts size and default object, and another that accepts an array, it does _not_ directly lead to a capability to mix those arguments into the same call.

Even today, there are sanity checks to prevent such things as

     Array.new(4, {}) { | i | i * i },

and such shall always be needed. And I feel that the warning that Ruby generates on evaluating the above, is very correct.

Am I seriously missing something in Daniel's argument?

Best regards,

JS

Berger, Daniel wrote:

···

-----Original Message-----
From: Yukihiro Matsumoto [mailto:matz@ruby-lang.org] Sent: Wednesday, March 01, 2006 4:46 PM
To: ruby-talk ML
Subject: Re: Confusion Over Keyword Arguments

<snip>

>How about "=" for keyword arguments instead
>(such as in python)?

Unfortunately, assignments are legal in argument list in Ruby.

              matz.

That can be made to work, with the understanding that '=' in a method
call means 'keyword argument', not 'assignment', since there is no point
in doing an assignment in a method call.

# Method definition, '=' means assignment (of default value):
def foo(bar, baz = 3)
   ...
end

# Method call, '=' means keyword
foo(baz = 5, bar = 2)

For anyone who cares to read my past thoughts on the subject:

If Python can do it... - Testing 1,2,3... — LiveJournal
The Price of Explicitness - Testing 1,2,3... — LiveJournal
Mo' Better Keyword Arguments - Testing 1,2,3... — LiveJournal
Better Keyword Arguments - Testing 1,2,3... — LiveJournal

Regards,

Dan

Hi --

From: Yukihiro Matsumoto [mailto:matz@ruby-lang.org]
Sent: Wednesday, March 01, 2006 4:46 PM
To: ruby-talk ML
Subject: Re: Confusion Over Keyword Arguments

<snip>

>How about "=" for keyword arguments instead
>(such as in python)?

Unfortunately, assignments are legal in argument list in Ruby.

              matz.

That can be made to work, with the understanding that '=' in a method
call means 'keyword argument', not 'assignment', since there is no point
in doing an assignment in a method call.

# Method definition, '=' means assignment (of default value):
def foo(bar, baz = 3)
  ...
end

# Method call, '=' means keyword
foo(baz = 5, bar = 2)

but is

foo baz = 5, bar = 2

a, b = foo(baz = 5), (bar = 2)

or

a = foo( (baz = 5), (bar = 2) )

You may have to bite the bullet and dust off your parentheses keys :slight_smile:
I've never been a big fan of things like:

    def meth a, b, c = 1

anyway. I don't think mandatory parens would be so bad... though I
know that's not a unanimous opinion.

I'm not sure about '=' in method calls for keyword arguments, though.
Then again, I'm not sure about keyword arguments, so I don't count :slight_smile:
(My concern is that I distrust anything that couples local variables
in one scope with, essentially, anything in any other scope.)

David

···

On Fri, 3 Mar 2006, ara.t.howard@noaa.gov wrote:

On Fri, 3 Mar 2006, Berger, Daniel wrote:

-----Original Message-----

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! Ruby for Rails

Yukihiro Matsumoto wrote:

Hi,

>That can be made to work, with the understanding that '=' in a method
>call means 'keyword argument', not 'assignment', since there is no point
>in doing an assignment in a method call.

I'm not sure if we _can_. yacc is a tough guy to fight with.

>http://djberg96.livejournal.com/50162.html

In this article, you've proposed *rest to slurp keyword hash. Indeed
it is simple, but maybe too simpler. I don't get how it can co-exist
with _your_ ideal keyword parameters. I.e. how the following code
should work?

def foo(a, b=0, *c)
    ...
end

foo(1, foo:3) # (a=1, b={:foo=>3}) or (a=1,b=0,c=[{:foo=>3}])?

Error. There's no 'foo' parameter. Passing a literal hash would require {}.

foo(1, 2, 8, c:5) # c={:c=>5}) or c=[8,{:c=>5}] or error?

Hm. Either an error or c = [5], depending on whether or not your want to declare that, once a positional is used, there's no going back after the fact.

args = [1, {:b=>2, foo=>5}]
foo(*args) # (a=1,b={:b=>2, foo=>5}) or (a=1,b=2,c=[{:foo=>5}])?

a = 1, b = {:b=>2, foo=>5}, since you've passed a literal hash.

Here's the latest test case we had for Sydney. Note that Sydney assumes that all method arguments automatically become keyword arguments. There's no syntax for explicitly declaring that a given method parameter is a valid keyword argument.

For the kids following along at home, also see http://redhanded.hobix.com/inspect/namedParametersArenTTheyAllNamed.html for further discussion on the subject.

Regards,

Dan

···

In message "Re: Confusion Over Keyword Arguments" > on Fri, 3 Mar 2006 00:57:44 +0900, "Berger, Daniel" <Daniel.Berger@qwest.com> writes:

#
# Tests the keyword argument behavior.
#
# Authored by Dan Berger and Evan Webb
#

require 'behavior/keyword'
require 'test/unit'

# This is the class we use within the test case below.
class Foo
    MYCONST = 5
    behavior KeywordBehavior

    attr_reader :x, :y, :z
    def bar(x, y, z=3)
       @x = x
       @y = y
       @z = z
    end

    def grab(x, y, *z)
       @x = x
       @y = y
       @z = z
    end

    def vars
       [@x, @y, @z]
    end

    def t2(x)
       name = "blah"
    end
end

# Added to test a method redefinition in a subclass, as well as the
# define_method and instance_method methods.
class Bar < Foo
    attr_reader :a, :b, :c
    def bar(a, b=2, c=3, d=4)
       @a = a
       @b = b
       @c = c
    end
    define_method(:baz, instance_method(:bar))
end

TOPLEVEL=5

class TC_Arguments < Test::Unit::TestCase
    def setup
       @foo = Foo.new
       @bar = Bar.new
       @arr = [1,2,3]
    end
  
    def test_methods_defined
       assert_respond_to(@foo, :bar)
       assert_respond_to(@bar, :bar)
       assert_respond_to(@foo, :grab)
       assert_respond_to(@foo, :vars)
       assert_respond_to(@foo, :t2)
       assert_respond_to(@bar, :baz)
    end
  
    # Methods may still take positional arguments, the way they always have
    def test_positional_basic
       assert_nothing_raised{ @foo.bar(1,2) }
       assert_nothing_raised{ @foo.bar(1,2,3) }
    end

    def test_positional_basic_subclass
       assert_nothing_raised{ @bar.bar(1) }
       assert_nothing_raised{ @bar.bar(1,2) }
       assert_nothing_raised{ @bar.bar(1,2,3) }
       assert_nothing_raised{ @bar.bar(1,2,3,4) }
       assert_nothing_raised{ @bar.baz(1,2,3) }
    end
  
    # You can use named parameters, using the name of the parameter defined in
    # in the method itself. It must be the name of the parameter, followed by
    # a colon, followed by the value. Spaces between the parameter name, colon
    # and value are not allowed.
    def test_named_basic
       assert_nothing_raised{ @foo.bar(z:1, x:2, y:3) }
       assert_equal(2, @foo.x)
       assert_equal(3, @foo.y)
       assert_equal(1, @foo.z)
    end

    def test_named_basic_subclass
       assert_nothing_raised{ @bar.bar(d:1, a:2, b:3, c:4) }
       assert_equal(2, @bar.a)
       assert_equal(3, @bar.b)
       assert_equal(4, @bar.c)
       assert_equal(1, @bar.d)
    end

    # Ensure that named parameters in a define_method/instance_method work.
    # In this case, Bar#baz is actually calling Foo#bar.
    def test_named_dynamically_defined
       assert_nothing_raised{ @bar.baz(z:3, y:2, x:1) }
       assert_equal(1, @bar.x)
       assert_equal(2, @bar.y)
       assert_equal(3, @bar.z)
    end
  
    # Default values in a declaration work the same way they always have. The
    # use of named parameters does not change this.
    def test_named_basic_default_values
       assert_nothing_raised{ @foo.bar(x:1, y:2) }
       assert_equal(1, @foo.x)
       assert_equal(2, @foo.y)
       assert_equal(3, @foo.z) # default
    end
  
    # You can mix and match positional and named parameters, though there are
    # limitations. Positional parameters must come first (i.e. on the left
    # side).
    def test_mixed_basic
       assert_nothing_raised{ @foo.bar(1, z:2, y:3) }
       assert_equal(1, @foo.x)
       assert_equal(3, @foo.y)
       assert_equal(2, @foo.z)
    
       assert_nothing_raised{ @foo.bar(1, 2, z:4) }
       assert_equal(1, @foo.x)
       assert_equal(2, @foo.y)
       assert_equal(4, @foo.z)
    end
  
    # You can splat an array, and the values will be assigned in a left to right
    # fashion, as in the current Ruby behavior.
    def test_splat
       assert_nothing_raised{ @foo.bar(*@arr) }
       assert_equal(1, @foo.x)
       assert_equal(2, @foo.y)
       assert_equal(3, @foo.z)
    end

    # You can mix and match positional, named and splat arguments. However,
    # splat arguments must come last. This is the same as the current behavior
    # in Ruby.
    def test_mixed_splat
       a = [1]
       assert_nothing_raised{ @foo.bar(*a) }
       assert_nothing_raised{ @foo.bar(1, *a) }
       assert_nothing_raised{ @foo.bar(1, y:2, *a)}
       assert_nothing_raised{ @foo.bar(1, 2, *a) }
       assert_nothing_raised{ @foo.bar(x:1, y:2, *a) }
    end

    # The '*rest' declarations work the same as they always have. In the case
    # of named parameters, the values assigned to the 'rest' argument are
    # simply pushed as an array.
    def test_def_splat
       assert_nothing_raised{ @foo.grab(1, 2, 3, 4) }
       assert_equal([1, 2, [3, 4]], @foo.vars)

       assert_nothing_raised{ @foo.grab(x:1, y:2, z:4) }
       assert_equal([1, 2, [4]], @foo.vars)

       assert_nothing_raised{ @foo.grab(1, 2, 3, [1,2,3])
       assert_equal([1,2,3,[[1,2,3]]], @foo.vars)

       assert_nothing_raised{ @foo.grab(1, 2, 3, z:[1,2,3])
       assert_equal([1,2,3,[[1,2,3]]], @foo.vars)

       assert_nothing_raised{ @foo.grab(1, 2, 3, z:*[1,2,3])
       assert_equal([1,2,3,[1,2,3]], @foo.vars)
    end

    # If a keyword argument is assigned to a '*rest' parameter, then it
    # autovivifies a hash, assigning that hash as the argument to the
    # '*rest' parameter. Note double declarations are still illegal.
    def test_keyword_in_splat
       assert_nothing_raised{ @foo.grab(10, 20, name:"evan", age:99) }
       assert_equal([ 10, 20, [{:name => "evan", :age=>99}] ], @foo.vars)
    end

    # If nothing is assigned to the '*rest' variable, then it is simply empty.
    # is the same as the current Ruby behavior.
    def test_keyword_no_splat
       @foo.grab(x:1, y:2)
       assert_equal [1,2,], @foo.vars
    end

    # The presence of a '*rest' declaration does not alter required arguments.
    def test_keyword_splat_with_not_enough
       assert_raises(ArgumentError) { @foo.grab(x:1) }
    end

    # Ensure that the presence of a parameter in one method declaration does
    # not interfere with an identically named parameter in another declaration.
    def test_no_local_leakage
       assert_nothing_raised { @foo.t2 x:8 }
    end

    # Ensure that "::" doesn't cause problems
    def test_works_with_constants
       assert_nothing_raised{ @foo.bar(y:1, x:2, z:Foo::MYCONST) }
       assert_nothing_raised{ @foo.bar(y: 1, x: 2, z: ::TOPLEVEL) }
    end

    def test_expected_argument_errors
       assert_raises(ArgumentError){ @foo.bar } # x & y missing
       assert_raises(ArgumentError){ @foo.bar(1) } # y missing
       assert_raises(ArgumentError){ @foo.bar(x:1) } # y missing
       assert_raises(ArgumentError){ @foo.bar(y:1) } # x missing
       assert_raises(ArgumentError){ @foo.bar(x:1, z:2) } # y missing
       assert_raises(ArgumentError){ @foo.bar([1,2,3]) } # y missing
       assert_raises(ArgumentError){ @foo.bar(*[1]) } # y missing
       assert_raises(ArgumentError){ @foo.bar(x:1,y:1,a:3) } # no 'a' parameter

       assert_raises(ArgumentError){ @foo.bar(*[1,2,3,4]) } # too many args
    end

    # Ensure that the subclass didn't pick up the named parameters
    # from the parent
    def test_expected_argument_errors_subclass
       assert_raises(ArgumentError){ @bar.bar }
       assert_raises(ArgumentError){ @bar.bar(x:1) }
       assert_raises(ArgumentError){ @bar.bar(y:1) }
       assert_raises(ArgumentError){ @bar.bar(z:1) }
    end

    def test_expected_syntax_errors
       assert_raises(SyntaxError){ @foo.bar(x:1, 2) } # positional must be first
       assert_raises(SyntaxError){ @foo.bar(*a, 1) } # splat must be last
       assert_raises(SyntaxError){ @foo.bar(*a, x:1) } # splat must be last
    end

    def teardown
       @foo = nil
       @arr = nil
    end
end

David Black wrote:

Then again, I'm not sure about keyword arguments, so I don't count :slight_smile:
(My concern is that I distrust anything that couples local variables
in one scope with, essentially, anything in any other scope.)

I completely agree. I kind of like the current technique of using an
"implicit" hash to pass named values.

I think the main attraction of keyword arguments is to let the caller
pass arguments in any order they want as long as they use the names.

But if I have so many arguments that it's hard for the client to
remember the order, then the arguments should probably be refactored
into a structure anyway (like a hash :slight_smile:

So to me keyword arguments are at best syntactic sugar and at worst a
way to cover-up code smells.

Jeff

···

--
Posted via http://www.ruby-forum.com/\.

Hi,

foo(1, foo:3) # (a=1, b={:foo=>3}) or (a=1,b=0,c=[{:foo=>3}])?

Error. There's no 'foo' parameter. Passing a literal hash would require {}.

I'm not sure what you meant by "literal hash". Do you mean foo:3 is
not legal since you don't have an argument with a name "foo"?

Have you changed your mind since the blog entry at
Better Keyword Arguments - Testing 1,2,3... — LiveJournal? For you have written

foo(1, 2, foo:4, bar:5) # a=1, b=2, c=[{'foo'=>4, 'bar'=>5}]
foo(1, 2, 8, baz:5) # a=1, b=2, c=[8, {'baz'=>5}]

in it. foo:4 etc. seems like non-literal hash.

args = [1, {:b=>2, foo=>5}]
foo(*args) # (a=1,b={:b=>2, foo=>5}) or (a=1,b=2,c=[{:foo=>5}])?

a = 1, b = {:b=>2, foo=>5}, since you've passed a literal hash.

This means that you cannot accept

(a) a keyword argument that is possibly accepted by the superclass's
     method, without knowing their names
(b) arbitrary keywords that can be passed to other methods

Right? If so, (a) means you need to have exact argument information
about a superclass method, which may not be available for mix-in
modules; (b) means there's no way to convert keyword arguments to a
hash.

Am I missing something?

              matz.

···

In message "Re: Confusion Over Keyword Arguments" on Fri, 3 Mar 2006 02:30:34 +0900, Daniel Berger <Daniel.Berger@qwest.com> writes:

Daniel Berger wrote:

Yukihiro Matsumoto wrote:

foo(1, foo:3) # (a=1, b={:foo=>3}) or (a=1,b=0,c=[{:foo=>3}])?

Error. There's no 'foo' parameter. Passing a literal hash would
require {}.

foo(1, 2, 8, c:5) # c={:c=>5}) or c=[8,{:c=>5}] or error?

Hm. Either an error or c = [5], depending on whether or not your want
to
declare that, once a positional is used, there's no going back after the
fact.

args = [1, {:b=>2, foo=>5}]
foo(*args) # (a=1,b={:b=>2, foo=>5}) or (a=1,b=2,c=[{:foo=>5}])?

a = 1, b = {:b=>2, foo=>5}, since you've passed a literal hash.

Here's the latest test case we had for Sydney. Note that Sydney assumes
that
all method arguments automatically become keyword arguments. There's no
syntax
for explicitly declaring that a given method parameter is a valid
keyword argument.

For the kids following along at home, also see
http://redhanded.hobix.com/inspect/namedParametersArenTTheyAllNamed.html
for
further discussion on the subject.

Regards,

Dan

Slightly off-topic but I found this part curious:

# You can use named parameters, using the name of the parameter

defined in

# in the method itself. It must be the name of the parameter,

followed by

# a colon, followed by the value. Spaces between the parameter

name, colon

# and value are not allowed.

Why is this? foo: bar would seem to be more legible with the
added benefit of no confusion with the scope operator :: nor
Symbols.

Your testcases do not seem to cover the scope completely and
Symbols are not included at all. Maybe add something like

  def test_corner_cases()
    # Symbols
    assert_nothing_raised {@foo.bar x:1, y:2, z::symbol}

    # Scopes
    assert_nothing_raised {@foo.bar A::B, y:2, z:3}
    assert_nothing_raised {@foo.bar x:1, y:2, z:::Object}

   assert_nothing_raised{ @foo.bar(z:1, x:2, y:3) }
  end # test_corner_cases

To cover those.

< snip rest of test cases />

E

···

--
Posted via http://www.ruby-forum.com/\.

Yukihiro Matsumoto wrote:

Hi,

>> foo(1, foo:3) # (a=1, b={:foo=>3}) or (a=1,b=0,c=[{:foo=>3}])?
>
>Error. There's no 'foo' parameter. Passing a literal hash would require {}.

I'm not sure what you meant by "literal hash". Do you mean foo:3 is
not legal since you don't have an argument with a name "foo"?

Have you changed your mind since the blog entry at
Better Keyword Arguments - Testing 1,2,3... — LiveJournal? For you have written

foo(1, 2, foo:4, bar:5) # a=1, b=2, c=[{'foo'=>4, 'bar'=>5}]
foo(1, 2, 8, baz:5) # a=1, b=2, c=[8, {'baz'=>5}]

in it. foo:4 etc. seems like non-literal hash.

Oops - I didn't notice you had declared it "*c" instead of "c". My blog entry is the expected behavior.

>> args = [1, {:b=>2, foo=>5}]
>> foo(*args) # (a=1,b={:b=>2, foo=>5}) or (a=1,b=2,c=[{:foo=>5}])?
>
>a = 1, b = {:b=>2, foo=>5}, since you've passed a literal hash.

This means that you cannot accept

(a) a keyword argument that is possibly accepted by the superclass's
     method, without knowing their names

I'm not sure I follow. How would you know the keyword arguments without knowing their names? Or are we getting into keyword discovery here?

(b) arbitrary keywords that can be passed to other methods

What do you mean by 'arbitrary keywords'?

Right? If so, (a) means you need to have exact argument information
about a superclass method, which may not be available for mix-in
modules;

I'm afraid I'm not following.

(b) means there's no way to convert keyword arguments to a

hash.

Are you talking internals, or by the user?

Well, anyway, I think this has all been gone over before. I probably should have just kept my mouth shut.

Dan

···

In message "Re: Confusion Over Keyword Arguments" > on Fri, 3 Mar 2006 02:30:34 +0900, Daniel Berger <Daniel.Berger@qwest.com> writes:

Daniel Berger wrote:

Yukihiro Matsumoto wrote:

not legal since you don't have an argument with a name "foo"?

Have you changed your mind since the blog entry at
Better Keyword Arguments - Testing 1,2,3... — LiveJournal? For you have written

foo(1, 2, foo:4, bar:5) # a=1, b=2, c=[{'foo'=>4, 'bar'=>5}]
foo(1, 2, 8, baz:5) # a=1, b=2, c=[8, {'baz'=>5}]

in it. foo:4 etc. seems like non-literal hash.

Oops - I didn't notice you had declared it "*c" instead of "c". My blog
entry
is the expected behavior.

>> args = [1, {:b=>2, foo=>5}]
>> foo(*args) # (a=1,b={:b=>2, foo=>5}) or (a=1,b=2,c=[{:foo=>5}])?
>
>a = 1, b = {:b=>2, foo=>5}, since you've passed a literal hash.

This means that you cannot accept

(a) a keyword argument that is possibly accepted by the superclass's
     method, without knowing their names

I'm not sure I follow. How would you know the keyword arguments without
knowing their names? Or are we getting into keyword discovery here?

(b) arbitrary keywords that can be passed to other methods

What do you mean by 'arbitrary keywords'?

I presume both this and the section before, Matz means
a situation like this:

  def actual_method(a, b, c, d)
    # ...
  end

  def delegator(*args, &block)
    actual_method *args, &block
  end

  delegator 1, 2, 3, d:4

The call is not really possible unless the keyword
'd' is automatically converted to a positional or
passed through in a hash or something like that.

The simple answer is that it is the responsibility
of the implementer of #delegator to map the call
so that no error is raised. This may not work in
cases where the whole of the dispatch is done
dynamically (although these may be quite rare).

Right? If so, (a) means you need to have exact argument information
about a superclass method, which may not be available for mix-in
modules;

I'm afraid I'm not following.

(b) means there's no way to convert keyword arguments to a

hash.

Are you talking internals, or by the user?

Well, anyway, I think this has all been gone over before. I probably
should
have just kept my mouth shut.

Dan

E

···

--
Posted via http://www.ruby-forum.com/\.