Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend module & class variable access?

Tags:

ruby

I can't understand why accessing module's class variable fails in the following example:

module M
  @@xyz = 123
end
M.class_variables    # [:@@xyz]
M.class_variable_get :@@xyz    # 123 , so far so good

class C
  extend M
end
C.singleton_class.class_variables    # [:@@xyz]
C.singleton_class.class_variable_get :@@xyz # NameError:
                      # uninitialized class variable @@xyz in Class

Can anybody explain why the class variable @@xyz is suddenly inacessible/undefined in C's singleton class?

Update: I re-tested the above code with different Ruby YARV versions and find it as a regression in the latest.

Update 2:

There was a change in definition of Module#class_variables method in latest Ruby generation.

  • Ruby up to 1.9.3 the definition is

    class_variables → array

    Returns an array of the names of class variables in mod.

  • Ruby 2.0.0 latest stable version

    class_variables(inherit=true) → array

    Returns an array of the names of class variables in mod. This includes the names of class variables in any included modules, unless the inherit parameter is set to false.

So in latest Ruby incarnation, class_variables returns by default also class variables of included modules. Just curious what's this feature for or if it still does concern modules "included" with include and not extend.

Can anybody explain ?

like image 650
David Unric Avatar asked Apr 19 '13 07:04

David Unric


People also ask

How do you extend a module in Ruby?

Extend is also used to importing module code but extends import them as class methods. Ruby will throw an error when we try to access methods of import module with the instance of the class because the module gets import to the superclass just as the instance of the extended module.

What's the difference between extend prepend and include?

The only difference is where in the ancestor chain the module is added. With include , the module is added after the class in the ancestor chain. With prepend, the module is added before the class in the ancestor chain.

How do I add a module in Rails?

You can include a module in a class in your Rails project by using the include keyword followed by the name of your module.

What is Module_function in Ruby?

module_function(*args) private. Creates module functions for the named methods. These functions may be called with the module as a receiver, and also become available as instance methods to classes that mix in the module. Module functions are copies of the original, and so may be changed independently.


2 Answers

Not sure if either of these are an answer, but I did find these

C::M.class_variables #=> ["@@xyz"]
# (but gives "warning: toplevel constant M referenced by C::M")

and

class D
  include M
end
D.class_variables #=> ["@@xyz"]

(This from Ruby 1.8.7, don't have a later version to hand right now).

include causes the module's instance methods to become instance methods of the class. According to Pickaxe, "It's almost as if the module becomes a superclass of the class that uses it".

Meanwhile, extend is intend to add a module's methods to an object; when called in a class definition it's equivalent to self.extend. It seems that they're not equivalent.

HTH.

like image 139
Mike Woodhouse Avatar answered Oct 24 '22 03:10

Mike Woodhouse


This is not answer, just some comments to the question.

If we include module M in class C, C gets class variables define in M:

module M
  @@xyz = 123
end

class C
  include M
end

C.class_variables   #=> [:@@xyz]
C.class_variable_get(:@@xyz)  # 123

To call extend M in class definition is equivalant as to call include M in eigen class (or singleton class) of that class.

module M
  @@xyz = 123
end

eigenclass = class C
  class << self
    include M
    self
  end
end

eigenclass.class_variables            #=>[:@@xyz]
eigenclass.class_variable_get(:@@xyz) #=>NameError: uninitialized class variable @@xyz in Class

It seems the difference lies on that Ruby treat normal classes and eigen classes differently.

like image 32
Arie Xiao Avatar answered Oct 24 '22 03:10

Arie Xiao