From: Robert Klemme Date: 2005-07-04T00:50:44+09:00 Subject: Re: class variable leading a double life "Eust�quio Rangel de Oliveira Jr." wrote: > Hey Robert! > >> Let me add to that that usually you want to associate a variable with >> the class instance or with instances. Class variables (the ones with >> @@) have some strange properties that sometimes lead to surprising >> behavior. I generally recommend to not use them. Instance >> variables in classes are much simpler to handle and much clearer and >> cleaner IMHO. > > Just to make things more clear, I'm not sure about "more clear" with your example... :-) > irb(main):001:0> class Test > irb(main):002:1> @@v1 = 0 # class variable? > irb(main):003:1> @v2 = 1 # ??? > irb(main):004:1> def initialize > irb(main):005:2> @v3 = 2 # instance variable? > irb(main):006:2> end > irb(main):007:1> def one > irb(main):008:2> @@v1 > irb(main):009:2> end > irb(main):010:1> def two > irb(main):011:2> @v2 > irb(main):012:2> end > irb(main):013:1> def three > irb(main):014:2> @v3 > irb(main):015:2> end > irb(main):016:1> end > => nil > irb(main):017:0> t = Test.new > => # > irb(main):018:0> t.one > => 0 > irb(main):019:0> t.two > => nil > irb(main):020:0> t.three > => 2 > > What is the correct names of v1, v2 and v3? v1 is a class variable, > but what about v2 and v3? We can say that v3 belongs to the class > instance (we saw that after creating the class v3 is on the output > )on t, but v2 belongs to the class Test? In fact you have v2, v2 and v3 which shows a bit unfortunate naming because these are three different things. They are all instance variables only that the first v2 is an instance variable of the class object while the second v2 is an instance variable of each Test instance. These are not the same nor do they interfere with each other. > The answer is the difference to create the variables just after the > class statement and before the initialize method OR create it in the > initialize method, right? Yes. And you can create them even later. Instance variables can spring into existing any time (i.e. during any method execution, see also #instance_variable_get, ..set etc). Ruby is different than other OO languages where you usually have to declare variables. In Ruby, you just use them. Whenever you do @something=x then the instance that is currently referred to by self will have an instance variable named "something". > And v2 is not reached by the two method, but if I change the class and > insert > > irb(main):026:0> class Test > irb(main):027:1> def self.four > irb(main):028:2> @v2 > irb(main):029:2> end > irb(main):030:1> end > > and use > > irb(main):032:0> t.class.four > => 1 > > I can reach it. So where v1 and v2 exactly are named and belongs to? I > can see that each t haves it's own v3, but still didn't get the way > the or ones are. How v1 and v2 are located on different places. > Kind of > > +-------+ +-----+ >> Test +-----+ t | > +-------+ +-----+ >> @@v1? | | @v3 | >> @v2? | +-----+ > +-------+ You're missing @v2 in the right object. > Maybe v1 and v2 are on the same place (the Test instance - v1 needs to > be shared by all Test's, right?) but just can be reached on different > ways (v2 using four)? Yes. > On the pickaxe we have an example > > class SongList > MaxTime = 5*60 # 5 minutes > def SongList.isTooLong(aSong) > return aSong.duration > MaxTime > end > end > > On this case, MaxTime resides on the same place that v2 or not? > Because if I change SongList and add > > class SongList > def isTooLong(aSong) > return aSong.duration > MaxTime > end > end > > and use > > s = SongList.new > s.isTooLong() > > I have a valid result, but something like > > irb(main):057:0> class SongList2 > irb(main):058:1> @maxtime = 5*60 > irb(main):059:1> def SongList2.isTooLong(t) > irb(main):060:2> return t > @maxtime > irb(main):061:2> end > irb(main):062:1> def isTooLong(t) > irb(main):063:2> return t > @maxtime > irb(main):064:2> end > irb(main):065:1> end > => nil > irb(main):066:0> s2 = SongList2.new > => # > irb(main):067:0> s2.isTooLong(301) > ArgumentError: comparison of Fixnum with nil failed > from (irb):63:in `>' > from (irb):63:in `isTooLong' > from (irb):67 > from (null):0 > irb(main):068:0> SongList2.isTooLong(301) > => true > irb(main):069:0> SongList2.isTooLong(30) > => false > > gives me that error, so there is also a scope difference on a constant > like MaxTime and a variable like @maxtime, defined on the class body? The trick is in the lookup: @something always refers to the current instance at the moment of execution. Your instance method isTooLong (which btw. in Ruby convention would be named too_long?) refers to a @maxtime instance variable of the SongList2 instance - as these instances don't have a @maxtime you get nil. Constants are looked up via in class scope - naturally because you cannot have constances in an instance. Kind regards robert