You can create instance variables of a class and define their accessors as singleton methods of that class.
But class variables like @@var
behave strangely, especially when inherited. Are there any use cases of it?
I interpret what you mean by strange as the fact that class variables are not different among each class but are shared among the inheritance hierarchy of classes.
As you mention and is also pointed out in Jörg W Mittag's answer to this question, it you wanted a variable to be consistent withing a class but differ outside of the class, then you can use a class instance variable on that class. That means, class variables should behave differently from that if it has any reason to exist. And class variables are indeed shared among classes within the inheritance hierarchy.
class A
@@foo = 3
end
class B < A
puts @@foo
end
# => 3
Probably, it may be useful when you want to share something that are common to classes in the hierarchy. For example, suppose you have some feature in a class that would be used in the classes that inherit this class. Suppose that that feature is dependent on a parameter, and you want that parameter change to be consistent among the classes that inherit that feature. Then, class variable will be useful.
For example, suppose you have this method:
class Array
def join_with_delimiter
join(@@delimiter)
end
end
class A < Array; end
By setting @@delimiter
once, you can expect consistent behavior across Array
and A
.
class Array; @@delimiter = "*" end
Array.new([:a, :b, :c]).join_with_delimiter # => "a*b*c"
A.new([:a, :b, :c]).join_with_delimiter # => "a*b*c"
class A; @@delimiter = "#" end
Array.new([:a, :b, :c]).join_with_delimiter # => "a#b#c"
A.new([:a, :b, :c]).join_with_delimiter # => "a#b#c"
If you do that with a class instance variable, you would not get consistent behavior:
class Array
def self.delimiter; @delimiter end
def join_with_delimiter
join(self.class.delimiter)
end
end
class A < Array; end
class Array; @delimiter = "*" end
Array.new([:a, :b, :c]).join_with_delimiter # => "a*b*c"
A.new([:a, :b, :c]).join_with_delimiter # => "abc"
class A; @delimiter = "#" end
Array.new([:a, :b, :c]).join_with_delimiter # => "a*b*c"
A.new([:a, :b, :c]).join_with_delimiter # => "a#b#c"