Skip to content

Instantly share code, notes, and snippets.

@sumanmukherjee03
Created October 19, 2012 00:17
Show Gist options
  • Save sumanmukherjee03/3915546 to your computer and use it in GitHub Desktop.
Save sumanmukherjee03/3915546 to your computer and use it in GitHub Desktop.
Messing with class variables in ruby
# Execute this file as follows and compare the results in ruby 1.8.*:
#
# ruby class_var_ex.rb
# ruby class_var_ex.rb "include module"
# ruby class_var_ex.rb "include module" "include global"
# ruby "include global"
@@test = 9 if ARGV.last == "include global"
module X
@@test = 3
self.instance_variable_set('@test', 4)
def get_class_variable_from_module
puts "Class variable from module = " + @@test.to_s
end
def get_class_instance_variable_from_module
puts "Class instance variable from module = " + @test.to_s
end
end
class A
extend X
@@test = 1
self.instance_variable_set('@test', 2)
def self.get_class_variable
puts "Class variable = " + @@test.to_s
end
def self.get_class_instance_variable
puts "Class instance variable = " + @test.to_s
end
end
class B < A
B.send(:include, X) if ARGV.first == "include module"
@@test = 2
self.instance_variable_set('@test', 1)
end
def extended_modules_class_variable
puts "Module's class variable = " + X.send(:class_variable_get, '@@test').to_s
end
def extended_modules_class_instance_variable
puts "Module's class instance variable = " + X.instance_variable_get('@test').to_s
end
puts "Values from A >>>>>>>>>>>>>>"
A.get_class_variable_from_module
A.get_class_instance_variable_from_module
A.get_class_variable
A.get_class_instance_variable
puts "Values from B >>>>>>>>>>>>>>"
B.get_class_variable_from_module
B.get_class_instance_variable_from_module
B.get_class_variable
B.get_class_instance_variable
puts "Values from X >>>>>>>>>>>>>>"
extended_modules_class_variable
extended_modules_class_instance_variable
if ARGV.last == "include global"
puts "Values from Global scope >>>>>>>>>>>>>>"
puts "Class variable = " + @@test.to_s
end
@sumanmukherjee03
Copy link
Author

@mekong, the behavior of the instance variables are totally expected. I punched them in there during the talk just to show the difference and create some context. However, i think the behavior has been resolved. The example i posted does not help answer the questions because i kept the variable names the same. Changing them opened up things.

In case of the class variables, the scope of the class variable in a child is the same as it's parent. So, changing the class variable of a child changes it's parent's class variable too and that behavior is retained through out. So, there is nothing confusing :-) .

I will post 2 more code samples to depict this.

When the module gets included, and the class variable @@test1 is redefined after the inclusion, module X becomes the immediate ancestor of the class B for look up and the class variable being changed in B points to the one initialized in the module X. The scope of that class variable is different than the scope of the class variable of the superclass A, because the superclass of X is not A. Here's the code sample depicting this.

module X
  @@test1 = 3
end

class A
  @@test1 = 9

  def self.get_class_variable
    puts "Class variable = " + @@test1.to_s
  end
end

class B < A
  include X
  @@test1 = 2

  def self.get_class_variable_from_module
    puts "Class variable from module = " + @@test1.to_s
  end
end

puts "Values from A >>>>>>>>>>>>>>"
A.get_class_variable

puts "Values from B >>>>>>>>>>>>>>"
B.get_class_variable_from_module
B.get_class_variable

When the module gets included, but the class variable @@test1 is redefined before the inclusion, the class variable being changed in B points to the one initialized in the class A. Here's the code sample depicting this.

class B < A
  @@test1 = 2
  include X

  def self.get_class_variable_from_module
    puts "Class variable from module = " + @@test1.to_s
  end
end

Continuing from the previous example, when you redefine the class variable again, after the inclusion, the pointer for the class variable changes to the one initialized in module X. So, both class A's class variable and the module X's class variable get changed. Here's the code depicting this.

class B < A
  @@test1 = 2
  include X
  @@test1 = 0

  def self.get_class_variable_from_module
    puts "Class variable from module = " + @@test1.to_s
  end
end

@sumanmukherjee03
Copy link
Author

@mikong and @Erol thanks for the effort and help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment