[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Named argument passing, and method_args extension

Brian Candler

9/6/2007 8:17:00 AM

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/0...

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] :-)

I had a look at http://eigenclass.org/hiki.rb?Changes+in+R... 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.

3 Answers

ry dahl

9/6/2007 4:46:00 PM

0

Method#args has a home now at http://method-args.ruby...
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

Rick DeNatale

9/7/2007 6:45:00 PM

0

On 9/6/07, Brian Candler <B.Candler@pobox.com> 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 http://eigenclass.org/hiki.rb?Changes+in+R... 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.denh...

enduro

9/10/2007 10:34:00 AM

0

Hello,

On Do, 2007-September-06 10:17:11, Brian Candler wrote:
> Quick question - what are the current thoughts about named argument passing
> in future versions of Ruby?
>
> [...]
> 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] :-)

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




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

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