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