# Named parameters in ruby?

**URL:** <https://www.ruby-forum.com/t/named-parameters-in-ruby/196091>\
**Category:** Ruby\
**Created:** [October 6, 2010, 6:06pm UTC](https://www.ruby-forum.com/t/named-parameters-in-ruby/196091 "2010-10-06T18:06:32Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![xiMera](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/x/85f322/32.png) [@xiMera](https://www.ruby-forum.com/u/xiMera)\
**Post date:** [October 6, 2010, 6:06pm UTC](https://www.ruby-forum.com/t/named-parameters-in-ruby/196091/1 "2010-10-06T18:06:32Z")

</div>

Hi all,

Ruby does not support named parameter for now as all of you know.  
There is really three solutions for this

- hash as parameter
- class as parameter
- bindings

Hash parameters:

def do\_some( params )  
a = params[:a]  
b = params[:b]  
end

do\_some :a =\> 1, :b =\>2

Class parameters (ugly, written in couple minutes)

class A  
def metaclass  
class \<\< self; self; end  
end

```
def set_var( name, val )
    eval "@#{name} = val", binding
    self.metaclass.send( :define_method, name ) do
        eval "@#{name}"
    end
end
def set_vars( params )
    params.each{ |key,val| self.set_var( key, val ) }
end

```

end

def do\_some( params )  
a = params.a  
b = params.b  
end

A.new  
a.set\_vars( :a =\> 1. :b =\>2 )  
do\_some a

Bindings way:

def do\_block( &block )  
eval “a=1”, block.binding  
eval “b=2”, block.binding  
end

do\_block( params ){  
a = eval ‘a’  
b = eval ‘b’  
}

As we can see there is overtyping in all cases. We always need to map  
incoming variables into locals or write ugly accessor every time.

So My question is:  
Is there any way to set local variables for blocks outside of block  
scope?

IMHO nice solution will looks like this:  
def do\_some( &block )  
block.binding.set\_var( ‘a’, 1 )  
block.binding.set\_var( ‘b’, 2 )  
block.call  
end

do\_some{  
puts a  
puts b  
}

---

<div class="post-metadata">

**Author:** ![xiMera](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/x/85f322/32.png) [@xiMera](https://www.ruby-forum.com/u/xiMera)\
**Post date:** [October 7, 2010, 4:53pm UTC](https://www.ruby-forum.com/t/named-parameters-in-ruby/196091/2 "2010-10-07T16:53:21Z")

</div>

On Wed, Oct 6, 2010 at 6:05 PM, xiMera [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> def do\_some( params )  
> a = params[:a]  
> b = params[:b]  
> end
> 
> do\_some :a =\> 1, :b =\>2

That’s really the best solution available today.

> ```
> eval "@#{name}"
> 
> ```
> 
> b = params.b  
> end
> 
> A.new

Where do you store result of A.new?

> a.set\_vars( :a =\> 1. :b =\>2 )  
> do\_some a

I don’t think anybody would do this, after all it’s much too  
convoluted. Also, why do you (ab)use a class for storing temporary  
state? You could as well do

A = Struct.new :a, b:  
do\_some A[1,2]

or

do\_some OpenStruct.new(:a=\>1,:b=\>2)

But even that is much more complicated than the Hash version. Plus,  
you do not get rid of the assignment in the block which you call  
“ugly” further on.

> }  
> Local assignments in the block are even worse. Also, this won’t run  
> because you pass one argument while the method expects none.

> As we can see there is overtyping in all cases. We always need to map  
> incoming variables into locals or write ugly accessor every time.
> 
> So My question is:  
> Is there any way to set local variables for blocks outside of block  
> scope?
> 
> IMHO nice solution will looks like this:

Frankly, I can’t see what’s nice about this approach.

> def do\_some( &block )  
> block.binding.set\_var( ‘a’, 1 )  
> block.binding.set\_var( ‘b’, 2 )  
> block.call  
> end
> 
> do\_some{  
> puts a  
> puts b  
> }

And what do you need that for? You can do this already today:

def do\_some  
yield 1,2  
end

do\_some do |a,b|  
puts a  
puts b  
end

Your solution with the “injection” of local variables cannot work  
because the variables are not known inside the block so Ruby will  
error out. Also, it is not obvious where the values are coming from  
so reading this code will be made harder.

I think your alternative solutions need a bit more polishing. 🙂

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![xiMera](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/x/85f322/32.png) [@xiMera](https://www.ruby-forum.com/u/xiMera)\
**Post date:** [October 7, 2010, 10:17pm UTC](https://www.ruby-forum.com/t/named-parameters-in-ruby/196091/3 "2010-10-07T22:17:40Z")

</div>

xiMera wrote:

> A.new  
> a.set\_vars( :a =\> 1. :b =\>2 )  
> do\_some a

I think you mean:

a = A.new  
a.set\_vars ( :a =\> 1, :b =\> 2)  
do\_some a

How is this better than

do\_some :a =\> 1, :b =\> 2

?

Note that if you are using ruby 1.9, then you can also write

do\_some a: 1, b: 2

which (from the caller’s point of view) is getting pretty close to named  
parameters.

At the callee’s side, multiple assignment keeps things pretty clean:

def do\_some(v={})  
a, b, c = v[:a], v[:b], v[:c]  
end

Or you can use values\_at, which is a bit longer in this case.

a, b, c = v.values\_at(:a, :b, :c)

Note that ruby needs to know at _parse_ time that a,b and c are local  
variables, so it can reserve slots for them in the activation record,  
and this assignment achieves that.

Any solution using eval to create local variables would be very  
inefficient, if it could be made to work at all.

irb(main):010:0\> def foo  
irb(main):011:1\> eval(“x = 5”)  
irb(main):012:1\> puts x  
irb(main):013:1\> end  
=\> nil  
irb(main):014:0\> foo  
NameError: undefined local variable or method `x' for main:Object from (irb):12:in`foo’  
from (irb):14  
from :0

---

<div class="post-metadata">

**Author:** ![xiMera](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/x/85f322/32.png) [@xiMera](https://www.ruby-forum.com/u/xiMera)\
**Post date:** [October 8, 2010, 11:29am UTC](https://www.ruby-forum.com/t/named-parameters-in-ruby/196091/4 "2010-10-08T11:29:25Z")

</div>

> def do\_some(v={})  
> Â a, b, c = v[:a], v[:b], v[:c]  
> end

One thing to remember about this idiom is what happens when you try  
and default the values:

(see [http://gist.github.com/616543](http://gist.github.com/616543) for the below code in a prettier  
format)

def foo(hash = { :a =\> 1, :b =\> 2 })  
a = hash[:a]  
b = hash[:b]  
puts a.inspect  
puts b.inspect  
end

foo

#=\>

# 1

# 2

foo(:a =\> 10)

#=\>

# 10

# nil

So you need something like

def foo(hash = {})  
hash = { :a =\> 1, :b =\> 2 }.merge(hash)  
a = hash[:a]  
b = hash[:b]  
puts a.inspect  
puts b.inspect  
end

foo

#=\>

# 1

# 2

foo(:a =\> 10)

#=\>

# 10

# 2

That whole requirement of doing merge is a little messy, I suppose;  
one reason that proper named/keyword arguments would be nice. Not too  
much of a problem, though, really.
