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.