From: Rick DeNatale Date: 2006-10-19T23:51:16+09:00 Subject: Re: modify instance variable in a method mixed in from external module On 10/18/06, hemant wrote: > I have this gem of a parser that does: > > def parse_data data > data.chomp! > while data && data.length > 0 > data_array = data.split(/\r?\n/,2) > @chunked_data << data_array[0] > data = data_array[1] > > if @chunked_data =~ /(\d{3})(.*)<(.*)>##(.*)##/ > dispatch_data > @chunked_data = "" > end > end > end > > > That is used in several classes as instance methods. Now, I want to > include this method in a module to be DRY. And make this method > available to classes that mixin that module. > The only trouble is, it uses a instance_variable. > Of course...i can keep this method as it is. assuming all the consumer > classes will have their this particular instance variable with same > name. Well, if the receiver of parse_data doesn't have the instance variable, it will after this method is executed. In Ruby, instance variables aren't declared/defined in classes, they are dynamically added to instances as needed. I'm not clear on just why you need @chunked_data to persist across invocations, but the only issue I see with guaranteeing that an instance of the class has this iv is that it's not guaranteed to be initialized, so in the first iteration of your while loop you might be doing nil << data_array[0] which won't work. This can be fixed by adding: @chunked_data ||= "" before the while loop. Now one danger is that a class might have an iv called @chunked_data which it's using for something else. This seems unlikely but you never know. If you do this you need to document the use of @chunked_data. There are likely better ways to design this if you step back a bit, but we don't know enough about the context to help. > The other approach could be, as suggested by Eric Hodel on IRC, is to > have some kind of include, that hookes correct instance variable to > the module upon inclusion in the class. I'm not sure what this means, so I can't comment. > And this bit..almost escaped me. > > If i use set_instance_variable or something like that, then still i > won't be able to know the name of that particular instance variable > ,right? > > if i pass the @chunked_data from the any class to the parse_data > method, i would recieve it as a local variable in method and any > changes to the varible will be lost. > Why can't we have something like C++ reference, where if i modify the > variable in mixed in method, i would effectively change the instance > variable? > Not even that, although in Ruby, AFAIK(which is very little, to tell > the truth) values are passed by reference, even if we pass a local > variable to the parse_data > method and do some modification and try to read back the data in > calling method, changes will be lost. In Ruby ALL variables are just references, if you mutate the object referenced by the variable the object will be changed: irb(main):005:0> def change(arg, value) irb(main):006:1> arg << value irb(main):007:1> end => nil irb(main):008:0> a = "hello" => "hello" irb(main):009:0> change(a, " there.") => "hello there." irb(main):010:0> a => "hello there." irb(main):011:0> Any mutating methods invoked against the parameter will change the underlying object. So rather than arg = "" you could use arg.replace("") Note that the value of a method is the value of the last expression executed in the method. So this method returns the value of arg << value So you could have parse return the chunked data and ask clients to pass it back on subsequent calls. I'm not saying that this is a good design, but you seem to need some understanding of how variables and objects relate. Another note on variables and references which trips up folks accustomed to C-like variables: irb(main):011:0> b = a => "hello there." irb(main):012:0> change(a, " Again!") => "hello there. Again!" irb(main):013:0> a => "hello there. Again!" irb(main):014:0> b => "hello there. Again!" Understand that and you should be further along in understanding the relationship between variables and object in Ruby. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/