Named argument passing, and method_args extension

Quick question - what are the current thoughts about named argument
passing
in future versions of Ruby? I’ve seen it requested in the past but not
much
in the way of concrete proposals.

Those awfully nice Merb people have just come up with a clever idea,
already
implemented as a small C extension. This lets you reflect on the names
of
arguments in a method definition.

require ‘method_args’
class X
def hello(foo, bar)
nil
end
end

x = X.new
meth = x.method(:hello)
meth.args? # => true
meth.args # => [‘foo’, ‘bar’] <<< cool!

This has been released as a Gem, see
http://rubyforge.org/pipermail/merb-devel/2007-September/000239.html

The idea is that instead of writing

def show
id = params[:id]
page = params[:page]

end

you should be able to write

def show(id, page=nil)

end

with Method#args allowing the desired elements of the params hash to be
picked out automatically and passed in the correct order.

Effectively what you end up is something like a splat call, but with the
arguments in named order as defined by the method definition.

Taking this one step further, has it been considered that splat might be
applied to a hash in the same way? e.g.

def func(a, b, c)
[a, b, c]
end

func( *{:c=>3, :b=>2, :a=>1} ) # => [1,2,3] :slight_smile:

I had a look at eigenclass.org but
couldn’t see anything along these lines.

In 1.8, splat does work on a hash, but only by flattening it to an
array
first, which isn’t very useful as the order is arbitary.

irb(main):003:0> def f(a); p a; end
=> nil
irb(main):004:0> f(
[1,2,3])
[1, 2, 3]
=> nil
irb(main):005:0> f(*{:a=>1,:b=>2})
[[:b, 2], [:a, 1]]
=> nil

Regards,

Brian.

P.S. By symmetry, I’d suggest that any ‘unused’ elements could be
available
as a hash too:

def func(a, b, c=3, *d)
p a, b, c, d
end

func( *{:a=>1, :b=>2, :e=>5, :f=>6} )

1

2

3

{:e=>5, :f=>6}

However this does mean that the receiver of *d would have to be able to
cope
with receiving either an Array or a Hash.

Method#args has a home now at http://method-args.rubyforge.org/
I released a new version too. It can be installed directly from the
command line

% sudo gem install method_args

There are several new methods for more refined sorcery:

% irb -r rubygems

require ‘method_args’
class X; def foo(hello, world = 2, *blah); end; end
method = X.new.method :foo
=> #<Method: X#foo>
method.required_args
=> [:hello]
method.optional_args
=> [:world]
method.splat_arg
=> :blah
method.args
=> [:hello, :world, :blah]

ry

On 9/6/07, Brian C. [email protected] wrote:

Quick question - what are the current thoughts about named argument passing
in future versions of Ruby? I’ve seen it requested in the past but not much
in the way of concrete proposals.

Those awfully nice Merb people have just come up with a clever idea, already
implemented as a small C extension. This lets you reflect on the names of
arguments in a method definition.

I had a look at eigenclass.org but
couldn’t see anything along these lines.

What IS in 1.9 is a new literal syntax for hash arguments:

$ irb1.9
irb(main):001:0> def test(arg)
irb(main):002:1> p arg
irb(main):003:1> end
=> nil
irb(main):004:0> test(a: “hello”, b: 3)
{:b=>3, :a=>“hello”}
=> nil

as an alternative to:

irb(main):005:0> test(:a => “hello”, :b => 3)
{:b=>3, :a=>“hello”}
=> nil

This allows all the current code which uses options hashs as a form of
named parameters to support a new “nicer” caller syntax without
change.

Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Hello,

On Do, 2007-September-06 10:17:11, Brian C. wrote:

func( *{:c=>3, :b=>2, :a=>1} ) # => [1,2,3] :slight_smile:

Wow, I really like this idea a lot.

I think this could be taken even a bit further,
by allowing the splat outside method headers:

h = {:c=>3, :b=>2, :a=>1}
a, b, c = *h
p [a, b, c] # => [1,2,3]

The most important reason why I like this,
is because it would give us not only named
arguments, but named return values too,
leading to a nice symmetry:

def get_data

{:name => name, :zip => zip}

the old way would be: [name, zip]

end

and then we would simply write:

name, zip = get_data

or just as well:

zip, name = get_data # same effect, more robust

Yes, hashes are already used to return multiple values today,
but I think the clumsy notation (
d = get_data
name = d[:name]
zip = d[:zip]
) prevents many programmers from adopting this practice.

To sum up:
Yes. I would really like to see something like this in Ruby 3.0

3

{:e=>5, :f=>6}

However this does mean that the receiver of *d would have to be able to
cope with receiving either an Array or a Hash.

OK, I would call that the problem of “reverse splatting”.

I.e.: If we allow splat for both arrays and hashes,
we will be able to determine the type of the splat from the object
if the operator is on the right-hand side.

But we won’t have any information, if it is on the left-hand side:
*x = a, b, c
This could be interpreted as both
x = [a, b, c]
or
x = {:a=>a, :b=>b, :c=>c}

A simple way to deal with that, would be to declare the old
interpretation
(array) as the only one for a LHS-splat.

And the semantics of Brian’s example could be preserved in this
approach,
because it not only has a LHS-splat, but also a RHS-splat with it.

Essentially it boils down to:
*d = *{:e=>5, :f=>6}

And we just have to assume an internal “splat reduction”, giving:
d = {:e=>5, :f=>6}

However, it might be nice to have a way to force reverse hash splatting,
for example by a new prefix operator **
**h = a, b, c

=> h = {:a=>a, :b=>b, :c=>c}

… but also inviting cans of trouble, like
**h = a, b, 42 # result??

perhaps

=> h = {:a=>a, b=>b, 2=>42} (position used as key)

Yes, at this point I really wish that there be a unified Hash-Array
data structure, as they have in Oz or Lua.

Bye for now

Regards
Sven