From: Ralph Shnelvar Date: 2009-11-29T05:21:38+09:00 Subject: Re: Class variables, instance variables, singleton; Ruby v. C++ Rick, I know I am top-posting but ... This has been super-helpful. It presents a helicopter view of what was, uh, mystifying me. :-) Many, many, thanks. Ralph Saturday, November 28, 2009, 7:46:26 AM, you wrote: RD> On Sat, Nov 28, 2009 at 8:00 AM, Ralph Shnelvar wrote: >> DAB> And of course this is one of the (many) problems with class variables: >> DAB> they make obscure the otherwise rather simple notion that classes can >> DAB> have instance variables because classes are objects and any object can >> DAB> have instance variables. >> >> David ... this may be the higher-level gestalt that I was missing. �It >> sure sounds like it. >> >> Let me flesh out my questions/comments about this paragraph so that you and >> others have something specific to answer. �Let's call the classed �F & >> G. >> >> (1) OK, classes are (i) objects; (ii) are executable code. RD> I wouldn't say that classes are executable code. However the RD> difference between Ruby and C++ here is that in C++ a class is really RD> just a C Struct definition with new features like virtual member RD> functions and inheritance. It's a static compile time construct. RD> In Ruby on the other hand, classes are defined at run time as code is RD> executed, and the stuff inside a class definition is executable code. RD> Another related difference is that in C++ the class describes which RD> instance variables are present in every instance of that class by RD> virtue of the instance variables (members) being statically declared. RD> In Ruby an object gets instance variables one by one only when it RD> executes a method which sets the instance variable. Since classes are RD> objects this applies to classes as well. RD> A primary purpose of a class is to collect method implementations RD> which will be part of the repertoire of instances of that class. RD> So for example RD> class A RD> # At this point the class has no class instance variables RD> @class_instance_variable1 = 42 # This statement is executed when RD> the class def is, so RD> # after this A RD> has a class instance variable RD> # The following defines a method which will be in the repertoire RD> of instances of A or any RD> # of its subclasses RD> def some_method RD> @instance_var = "Hello" RD> end RD> # The self. makes the following a method of the class A. We RD> call this a class method RD> # it will also be in the repertoire of any class objects which RD> subclass A (but not their instances) RD> def self.a_class_method RD> @class_instance_variable2 = [1, 2, 3] RD> end RD> end RD> a = A.new RD> # At this point of execution: RD> # RD> # The class A has ONE class instance variable @class_instance_variable1 RD> # RD> # a, which is an instance of A, has NO instance variables RD> a.some_method RD> # And now a has an instance variable named @instance_var RD> A.a_class_method RD> # And now A has another class instance variable @class_instance_variable2 >> (2) If I do the following >> � � �class F >> � � �end >> � � �f = F.new >> � � �F.class �# class >> � � �f.class �# F >> this makes sense to me. >> >> What (relevant and important conceptually) messages (other than "new") >> can I send to a class? �But see (3), below. RD> Well like any object the answer to that depends on the class. All RD> classes are instances of Class, which defines three methods, only two RD> of which are normally called by user code. RD> Class#allocate which actually allocates the storage for a new RD> instance, this is rarely if ever overriden or called directly RD> Class#new which calls allocate to get a new instance and then calls RD> intialialize on the new instance passing any arguments along. This is RD> called often but rarely overridden. RD> Class#superclass which returns the superclass of the class, again RD> called but almost never overridden. RD> In addition Class is a subclass of Module, and inherits from module RD> the ability to collect methods and to serve as a nested namespace. So RD> every class object has the instance methods defined in Module as part RD> of its repertoire, I'll leave you to look these up. RD> And of course the instance methods defined in Object and the module RD> Kernel (which is included by Object) are part of the repertoire of RD> very Object and therefore every object which happens to be a class. RD> Some Ruby standard library classes like Array, Dir, File and others RD> define additional class methods specific to the class and its RD> subclasses. >> (3) >> � �class F >> � � �def sub1 >> � � � �@@x = 1 >> � � �end >> � �end >> >> � �class G >> � � �self.sub1 >> � � � �@@x=2 >> � � �end >> � �end >> >> � �# Why? �Didn't the interpreter "see" @@x in class F? >> � �F.class_variables �# [] RD> See my explanation above. In this regard class variables like RD> instance variables RD> F doesn't have any class variables because the sub1 method hasn't been executed. RD> G does because you execute sub1 inside its class definition code. I RD> assume that you actually defined G as a subclass of F or you would RD> have gotten an undefined sub1 method error. RD> And you have invalid syntax in that snippet because there's an extra end RD> class G RD> self.sub1 RD> @@x = 2 RD> end # this ends the class def which consists of two RD> end >> � �# makes sense >> � �G.class_variables �# ["@@x"] >> >> � �f = F.new >> >> � �# Why? �Shouldn't the method inherit from the class? >> � �f.class_variables �# undefined method RD> Because f is an instance of F, and is not a class, class_variables is RD> a method defined in Module, not Object or kernel >> >> � �f.sub1 �# 1 >> >> � �# makes sense. �class variable now explicitly executed >> � �F.class_variables # ["@@x"] >> >> � �# How to use class_variable_get if the method is private??? >> � �F.class_variable_get(:@@x) �# error private method! RD> F.send(:class_variable_get, :@@x) RD> As others have pointed out class variables are a pretty wonky area of RD> Ruby. In Ruby 1.8 if G is a actually a subclass of F, then whether or RD> not @@x is the same instance variable for both depends in some cases RD> on whether or not F got its instance variable before G did or not. RD> When a class variable is initialized Ruby 1.8 looks through the chain RD> of superclasses to see if a class variable with that name already RD> exists, and if so uses that definition. If not it defines it for the RD> current class. Ruby 1.9 changed that so that now class variables are RD> no longer shared with subclasses. RD> Now it may seem hard or harsh, but I'd recommend that you try to RD> forget what you know about C++ when learning Ruby. RD> Although C++ and Ruby are both said to be object-oriented, they come RD> from two very different views of what that means. C++ is the epitome RD> of what Ralph Johnson calls the "Software Engineering" school, where RD> objects are seen as an extension of abstract data types. Ruby is of RD> what he calls the "Mystical" school where objects are seen as entities RD> which encapsulate both the data representation and the methods which RD> operate on the data, and which interact with other objects only by RD> message invocation of methods, looked up by name at runtime. Java is RD> influenced by the SE school, but is more dynamic in other regards. RD> Other mystical languages include Smalltalk, Self, and JavaScript RD> although JavaScript is not fundamentally OO. -- Best regards, Ralph mailto:ralphs@dos32.com