From: Brian Candler Date: 2007-03-08T18:01:02+09:00 Subject: Re: Setting default vales 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.