I'm still learning my way around ruby and I seem to be confused about class methods/variables versus instance methods/variables. My example comes from Ruby on Rails, but I don't think my confusion is rails- specific. In ActiveRecord::Base, there is a method columns. I initially thought this was an instance method since it wasn't declared as ActiveRecord::Base.columns, which is the required syntax for class methods. However someone explained to me that you can enclose several method declarations in a class << self block which makes them all class methods. OK, so columns is a class method. But then in its source, it makes reference to the instance variable @columns. In other OOP languages that I'm familiar with, it's forbidden to access instance variables within a class method (if the class hasn't been instantiated, then the instance variables can't have been initialized). I've investigated the situation in ruby, and apparently it is this: it's not illegal to reference an instance variable from within a class method, but the instance variable will be nil. In the rails scaffolding, the code calls Modelname.columns. So it's calling the class method, and the class has not been instantiated. Help de-confuse me! How does this class method get away with referencing an instance variable and where exactly does this instance variable get initialized? (I can't find any occurrences of @columns outside of other class methods, so it's apparently not being initialized anywhere in this class?) Thanks in advance, zig
on 2007-03-24 22:51
on 2007-03-24 23:07
zig wrote: > class methods. > > OK, so columns is a class method. But then in its source, it makes > reference to the instance variable @columns. In other OOP languages > that I'm familiar with, it's forbidden to access instance variables > within a class method (if the class hasn't been instantiated, then the > instance variables can't have been initialized). I've investigated > the situation in ruby, and apparently it is this: it's not illegal to > reference an instance variable from within a class method, but the > instance variable will be nil. Not quite. The difference between Ruby and other languages is that *the class itself is an object*. This means that when you refer to an instance variable in a class method, you're referring to an instance variable of the class object itself, not the instance variable of any instances of that class. > In the rails scaffolding, the code calls Modelname.columns. So it's > calling the class method, and the class has not been instantiated. > > Help de-confuse me! How does this class method get away with > referencing an instance variable and where exactly does this instance > variable get initialized? (I can't find any occurrences of @columns > outside of other class methods, so it's apparently not being > initialized anywhere in this class?) In this case, it's an instance variable on the Modelname class which, as I rather confusingly explain above, is also an object - it's an instance of class Class. Clear as mud? :-)
on 2007-03-24 23:29
Alle sabato 24 marzo 2007, zig ha scritto: > class methods. > In the rails scaffolding, the code calls Modelname.columns. So it's > calling the class method, and the class has not been instantiated. > > Help de-confuse me! How does this class method get away with > referencing an instance variable and where exactly does this instance > variable get initialized? (I can't find any occurrences of @columns > outside of other class methods, so it's apparently not being > initialized anywhere in this class?) > > Thanks in advance, > zig I don't know rails at all, so I may be completely wrong. Classes (in this case the class ActiveRecord::Base) are themselves instances of the class Class (try writing ActiveRecord::Base.is_a?(Class): it returns true), so they can have instance variables, too (here I'm not referring to instance variables of instances of the class, i.e of instances of ActiveRecord::Base, but to instance variables of the class ActiveRecord::Base itself). Instance variables of a class can be created whenever self is the class, usually in the definition of the class or in a class method. Instance variables of the class can used in class methods of that class, which actually are simply singleton instance methods of the class. To make this explaination a bit more clear, here's a simple example (comments refer to the line of code above them: class MyClass # Here, we're creating an instance of class Class and storing it in a constant # called MyClass def method_1 # Here, we're defining an instance method, i.e a method which can be called # on instances of class MyClass (for example, on the object returned by # MyClass.new @var=1 # Here, we create an instance variable. Since self is an instance of # MyClass, this is an instance variable of an instance of MyClass puts "This is method_1" end @cls_var=2 # Now, self is MyClass, so @cls_var is an instance variable of the class # itself. It can't be called by instances of MyClass def MyClass.cls_method_1 # Here, we're defining a class variable, i.e a singleton method of MyClass. # (Note that the syntax is the same used for defining a singleton method in # other circumstances) puts "This is cls_method_1" puts "@cls_var is #{@cls_var}" # Here, self is MyClass, so we can access its instance variables end class << self # This idiom is used to access an object's singleton class (in this case, # MyClass's singleton class. From now until the corresponding end, # MyClass will behave as an instance of the current class def cls_method_2 # Here we're defining an instance method. Since the instance of the current # class is MyClass, this is a class method for MyClass puts "This is MyClass.cls_method_2" puts "@cls_var is #{@cls_var}" # Here, we show again that we can access the instance variable of the class end end # Here, we exit the singleton class def method_2 # We define a new instance method for MyClass (this will be called on # instances of MyClass puts "This is method_2" puts "@cls_var is #{@cls_var.inspect}" # Here we can't access instance variables of MyClass, and we see it # (inspect is used to display nil instead of an empty string) end end Some tests on the above: MyClass.cls_method_1 => This is MyClass.cls_method_1 @cls_var is 2 MyClass.cls_method_2 => This is MyClass.cls_method_2 @cls_var is 2 MyClass.new.method_1 => This is method_1 MyClass.new.method_2 => This is method_2 @cls_var is nil I hope this helps (and doesn't create additional confusion). Sorry for the length of the post. Stefano
on 2007-03-24 23:57
The usual Java thing of "this is a class, this thing is an instance of
that class" places classes **themselves** outside of the set of usable
objects in the language.
Ruby does not do this. Because a Ruby class is an instance of Class,
it's as open to the programmer as anything else in Ruby.
(This model is adopted directly from Smalltalk.)
What this means is that classes in Ruby aren't these ideal Platonic
objects that sit outside of the world the programmer interacts with.
They're something you can rewrite in real time. There's no real
difference between a class and an object.
Here's the code you're looking at. It's inside a class << self block
which adds it to any class which inherits from ActiveRecord::Base.
# Returns an array of column objects for the table associated
with this class.
def columns
unless @columns
@columns = connection.columns(table_name, "#{name} Columns")
@columns.each {|column| column.primary = column.name ==
primary_key}
end
@columns
end
The answer to your question is that the class which inherits is opened
up, and this method is defined within it. Not the instances -- the
instances are untouched. This opens up the Class object itself. Then,
obviously, it sets an instance variable. At that point, what it's
doing is setting an instance variable of the Class object.
What's actually happening here is pretty simple. You're opening up
another object and assigning an instance variable to it. That's all.
The other object just happens to be a Class object.
on 2007-03-25 03:41
On Mar 24, 3:56 pm, "Giles Bowkett" <gil...@gmail.com> wrote: > The answer to your question is that the class which inherits is opened > up, and this method is defined within it. Not the instances -- the > instances are untouched. This opens up the Class object itself. Then, > obviously, it sets an instance variable. At that point, what it's > doing is setting an instance variable of the Class object. > OK, I think I'm getting there. Is an instance variable of the class object the same thing as a class variable? For example, consider class A @@var1 end and class A class << self attr_reader :var1 attr_writer :var1 end end In both cases I call that variable with A.var1. Are they the same?
on 2007-03-25 03:53
zig wrote: > > > > > A class variable is NOT the same as an instance variable of the class object. Have you tried "calling" @@var1 with A.var1? It doesn't work. The attr_reader and attr_writer methods create methods that operate on @var1. There is no method "var1" that operates on @@var1.
on 2007-03-25 04:16
On Mar 24, 6:52 pm, Timothy Hunter <TimHun...@nc.rr.com> wrote: > > A class variable is NOT the same as an instance variable of the class > object. Have you tried "calling" @@var1 with A.var1? It doesn't work. > The attr_reader and attr_writer methods create methods that operate on > @var1. There is no method "var1" that operates on @@var1. You're right, that method isn't defined in the first case, I've just tried it. It also fails because class variables are required to be initialized, which I didn't do. So how about this? class A @@var1 = 2 def A.var1 @@var1 end end class A class << self @var1 = 2 def var1 @var1 end end end I tried this in irb as well, and again, they're not the same, but I can't figure out why not. This time the first declaration gives A.var1 => 2, while the second gives A.var1 => nil. But what happened to my 2?
on 2007-03-25 09:55
Alle domenica 25 marzo 2007, zig ha scritto: > So how about this? > @var1 = 2 > to my 2? In the second case, you have set @var1 to 2 in the context of the singleton class of A, not in the context of A, so it becomes an instance variable of the singleton class of A, not an instance variable of A. var1, instead is a class method of A, so inside its definition, self is A. Ruby will look for an instance variable called @var1 defined for A, it won't find it and will create a new one set to nil. To make the code work, you only need to move the line @var1=2 above the line class << self. This way, @var1 will become an instance variable of A and everyting will work. Regarding the difference between class variable and class instance variables: they have nothing in common. They can be accessed by instances of the class (and even created in instance methods) and are shared between a class and its descendents. A class instance variable is private to the class, and can't be accessed by the outside unless you provide suitable methods. In other threads on this list, it was suggested that it's best to avoid class variables and use class instance variables or constants instead (I don't know whether this is true or not, I'm only reporting). I hope this helps Stefano
on 2007-03-25 20:46
OK, I think I've got it now. Class methods of the class have access to class variables, class instance variables, but not instance variables. Instance methods of the class have access to class variables, instance variables, but not class instance variables. Class variables are accessible to both, but neither class instance variables nor instance variables are. Therefore class instance variables are not the same thing as class variables. Thanks Stefano, and all the others who replied!
on 2007-03-25 20:50
On Mon, Mar 26, 2007 at 03:45:10AM +0900, zig wrote: > OK, I think I've got it now. Class methods of the class have access > to class variables, class instance variables, but not instance > variables. Instance methods of the class have access to class > variables, instance variables, but not class instance variables. > Class variables are accessible to both, but neither class instance > variables nor instance variables are. Therefore class instance > variables are not the same thing as class variables. Also: class variables are also accessible to subclasses. Class instance variables belong only to one class. For them, a subclass is a completely different class object. Regards, Brian.
on 2007-03-26 02:17
On Mar 25, 2007, at 2:45 PM, zig wrote: > OK, I think I've got it now. Class methods of the class have access > to class variables, class instance variables, but not instance > variables. Instance methods of the class have access to class > variables, instance variables, but not class instance variables. > Class variables are accessible to both, but neither class instance > variables nor instance variables are. Therefore class instance > variables are not the same thing as class variables. It is also important to realize that class variables ('@@xyz') are resolved lexically. They are not resolved relative to 'self' but instead relative to the surrounding lexical scope (top-level, file, module blocks, class blocks). This is very different than instance variables ('@xyz') which are always resolved relative to 'self'. class A @@example = 1 puts @@example # 1, lexically associated with A def self.example @@example end end puts @@example # error, lexically associated with top-level # but not defined yet. def A.top_level_example @@example # top level @@example!!!! end @@example = 2 puts A.top_level_example # 2, gets @@example relative to top-level puts A.example # 1, gets @@example relative to A Gary Wright
on 2007-03-30 07:22
On Mar 25, 11:42 am, "zig" <ziggur...@gmail.com> wrote: > Therefore class instance > variables are not the same thing as class variables. > One thing we _can_ say is that class instance *methods* are the same thing as class methods, right? In fact, the term "class instance method" doesn't exist as a distinct concept, precisely because they are the same. I think this must have been the source of my confusion about class instance variables versus class variables.
on 2007-03-30 08:14
On Mar 30, 2007, at 1:20 AM, zig wrote: > On Mar 25, 11:42 am, "zig" <ziggur...@gmail.com> wrote: >> Therefore class instance >> variables are not the same thing as class variables. >> > > One thing we _can_ say is that class instance *methods* are the same > thing as class methods, right? In fact, the term "class instance > method" doesn't exist as a distinct concept, precisely because they > are the same. I'm not sure that 'class instance methods' is a well-defined term. I think what you are after is instance methods of a singleton class of a class are the same as singleton methods of a class are the same as class singleton methods are the same as class methods Via irb: >> Array.singleton_methods => ["[]"] >> Regexp.singleton_methods => ["escape", "quote", "last_match", "compile", "union"] >> Time.singleton_methods => ["rfc822", "gm", "zone_offset", "parse", "iso8601", "rfc2822", "utc", "xmlschema", "today", "at", "mktime", "now", "_load", "httpdate", "local", "times"] But 'Class instance methods' is well-defined: >> Class.instance_methods(false) => ["new", "superclass", "allocate"]
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.