Setting default vales

Hello,

I want to have some function that will two parameters. First is the
variable name and second is a value.
Inside I will check:

  • if the variable is existed I do nothing
  • else I assign “value” to variable

It should be something like this but it is not working.

def set_default(name, val)
if ! name then
eval “#{name} = #{val}”
end
end

set_default(“b”, “2”)
puts "b = " + b

On 3/7/07, Mike [email protected] wrote:

def set_default(name, val)
if ! name then
eval “#{name} = #{val}”
end
end

set_default(“b”, “2”)
puts "b = " + b

The first deception will come from this little snippet I am afraid,
cat default.rb && echo “--------------” && ruby default.rb

vim: sts=2 sw=2 nu expandtab nowrap:

a = 42
def test_a
defined? a
end
p test_a

nil

As you can see a is not visible inside the method.
Let us try to find a different tool for that

vim: sts=2 sw=2 nu expandtab nowrap:

a = 42
test_a = proc {
defined? a
}
p test_a.call

“local-variable”

Which is better, we could now try to implement what you want as a proc

vim: sts=2 sw=2 nu expandtab nowrap:

a = 42
default = proc { |name, value|
eval “defined? #{name} ? nil : #{name} = #{value}”
}
default.call :a, 43
default.call :b, 43
puts a
puts b

42
def_proc.rb:9: undefined local variable or method `b’ for main:Object
(NameError)
What is happening here?
Well we cannot make b spring into live outside the proc scope.

This all just to ask two questions
Why using local variables and not instance variables? look at snippet
(1) below

Is the name ||= value syntax not good enough? I know it will overwrite
nil and false values but more often than not it is quite good enough.

If you really need what you want you will need some help from meta
programming gurus. If I am not mistaken this can be done with things
like binding_from_caller
as can be found in Facets, also have a look at Maurico Fernandez’ site
http://eigenclass.org/

HTH.
Robert
(1)

vim: sts=2 sw=2 nu expandtab nowrap:

@a = 42
def default name, value
return if instance_variables.include? name

There even is instance_variable_exists? in

1.8.6

instance_variable_set name, value
end
default “@a”, 43
default “@b”, 43
puts @a
puts @b

Thank you for your answer.
But it looks like this is a real problem for Ruby to use such
construct.
probably there is some other way (I don’t like to use @) to solve it.
Could I get a left side of “=” by some reference?
For example,
b = my_func(def_val)
Could I redefine “=” and get some information on “b”? And if b is
invalid I’ll return “def_val” otherwise I’ll return “b” itself.

Also, can I pass a “reference”/“pointer” into function?

On 3/7/07, Mike [email protected] wrote:
Please Mike try not to top post unless you need to, normally we prefer
to post after the text one is referring to.

Thank you for your answer.
But it looks like this is a real problem for Ruby to use such
construct.
probably there is some other way (I don’t like to use @) to solve it.
Could I get a left side of “=” by some reference?
For example,
b = my_func(def_val)
Could I redefine “=” and get some information on “b”? And if b is
invalid I’ll return “def_val” otherwise I’ll return “b” itself.

Well I tried hard with Binding.of_caller from facet but maybe I miss
something.
As I mentioned before I am not a metaprogramming guru :frowning:

Also, can I pass a “reference”/“pointer” into function?
Well all parameters are passed as references - even if there is a
studied discussion if this terminology is 100% correct.

try e.g.
a=“Hi there”
def change s
s << “!!!”
end
change a
puts a

On Mar 7, 8:55 pm, “Robert D.” [email protected] wrote:

On 3/7/07, Mike [email protected] wrote:

Cheers
Robert
We have not succeeded in answering all of our questions.
In fact, in some ways, we are more confused than ever.
But we feel we are confused on a higher level and about more important
things.
-Anonymous

Well I tried hard with Binding.of_caller from facet but maybe I miss
something.
As I mentioned before I am not a metaprogramming guru :frowning:

:slight_smile:

puts a

Probably it works with strings but try following code:

def test_change(var, val)
var = val
end

myvar = 5
test_change(myvar, 10)
puts myvar.to_s

On 3/8/07, Michael S. [email protected] wrote:

Well all parameters are passed as references - even if there is a

Probably it works with strings but try following code:

def test_change(var, val)
var = val
end

myvar = 5
test_change(myvar, 10)
puts myvar.to_s

They second I sent the mail I knew I was not precise enough :frowning:

Variables themselves are passed as values, stupid me how could I have
been so imprecise.
Only that all variables are than references to objects which can be
changed unless they are immutable.

thy Michael and sorry for my hasty post

Robert

On Thu, Mar 08, 2007 at 07:10:08AM +0900, Mike wrote:

Thank you for your answer.
But it looks like this is a real problem for Ruby to use such
construct.
probably there is some other way (I don’t like to use @) to solve it.
Could I get a left side of “=” by some reference?

Free your mind a little :slight_smile: Allow for the possibility that there might
be a
problem in how you’re approaching this, rather than how Ruby works. (I
was
very bad in this regard in the early days; I would dread to go back and
find
my early postings to ruby-talk).

In Ruby, almost everything is an object. That means: you access it via
an
object reference.

However, local variables are not objects. You cannot take a reference
to
them, nor alias them. They are simply placeholders which contain a
reference to an object.

Could Ruby have been designed so that local variables were themselves
objects? Perhaps. Why wasn’t it done? Because the Ruby approach is much
more
efficient. Ruby local variables are just slots in the stack frame, at a
fixed offset, and are therefore very cheap to use.

So whilst Ruby is an extremely dynamic language - objects and classes
can be
created on the fly, instance variables added to and removed from
objects,
even methods added to objects - this doesn’t apply to local variables
themselves, which just refer to these objects. As you’ve found, if you
want
to create a local variable on the fly, you have to jump through huge
hoops.

Hence the real answer is: just don’t do it. Show us a real problem which
involves you creating a local variable on the fly, and we’ll show you a
much
better way of doing it in Ruby. When you realise how easy it is to
define
and create objects, then you’ll find that almost certainly an object is
the
correct container for the state you’re trying to build, not the stack
frame.

Also, can I pass a “reference”/“pointer” into function?

All objects are passed by reference, even things like classes:

def make_a(klass) # note (*) below
return klass.new
end

class Foo
def hello
puts “hello!”
end
end

k = Foo
f = make_a(k)
f.hello

But as I said above, a local variable isn’t an object, and you can’t
take a
reference to it. That is, make_a(k) passes, by value, the object
reference
which k contains, not a reference to the local variable k itself.

Now, if you want to be able to change which object k points to, then
simply
return a new object reference:

k = change_it(k) # after this, k can refer to a new object

But much more often in Ruby, you’ll change the state of the object
itself:

change_it(k) # doesn’t change which object k points to, but
# changes the internal state of object k

or more idiomatically:

k.change_it # now the ‘change_it’ code is a method belonging
# to object k, or k’s class

I want to have some function that will two parameters. First is the
variable name and second is a value.
Inside I will check:

  • if the variable is existed I do nothing
  • else I assign “value” to variable

The Ruby idiom for this is not to call a function, but just to write:

foo ||= "my_default_value"

This is a shorthand notation for:

foo = foo || "my default value"

The || operator returns the LHS if it is not nil or false; otherwise it
evaluates and returns the RHS. Of course the RHS can be a complex
expression, or a function (method) call:

def make_default_foo(x,y,z)
  ... return a value based on x,y,z or whatever
end

foo ||= make_default_foo(17, 4, Time.now)

Hope this is clear,

Brian.

(*) All arguments to a function/method are object instances, so here
‘klass’
is an object instance. If you prefer, what’s passed is really a
reference
to an object instance, but you can quickly stop saying “…a reference
to…” since this is always the case in Ruby.

The intention of this particular function is that the argument is an
instance of a ‘Class’ object. But actually it doesn’t have to be; it
could
be any object which has a ‘new’ method. If you pass in any object which
doesn’t have a ‘new’ method, you’ll get a “method missing” error at
runtime
when it tries to invoke this method.

On Thu, Mar 08, 2007 at 11:36:58AM +0900, Michael S. wrote:

def test_change(var, val)
var = val
end

myvar = 5
test_change(myvar, 10)
puts myvar.to_s

That’s because:

(1) “<<” is a method call, but “=” is not (it’s an assignment to a local
variable)

(2) Strings are mutable, but numbers are not. That is, there’s no method
call you can make on the number ‘5’ which will change its value to
something
else :slight_smile:

So you either return the new number:

def change(val)
val + 1
end

myvar = 5
myvar = change(myvar)
puts myvar

Or you wrap it in an object:

class Myvar
attr_accessor :v
def initialize(v = nil)
@v = v
end
def to_s
@v.to_s
end
end

def test_change(obj, newval)
obj.v = newval
end

myvar = Myvar.new(5)
test_change(myvar, 10)
puts myvar.to_s

The notation “attr_accessor :v” is short for:

def v
@v
end

def v=(nv)
@v = nv
end

So when you write obj.v = newval, you are calling v=(newval) on the
object.

Regards,

Brian.