What is difference between class variable and variable defined on class level - ruby

What is the difference between class variable and variable defined on the class level?
say, bar is defined with ## which means it's a class variable and will be accessible within all methods in class.
class Foo
##bar = 'bar'
end
so does bar without ##, so what is the difference..?
class Foo
bar = 'bar'
end

Well, with your second option, bar is a local variable which gets out of scope when reaching the end. As such, it won't be accessible to any methods (class methods nor instance methods) of the class.
With that being said, in Ruby, there are class variables (##bar which are shared between all child classes and their instances and instance variables (#bar) Since classes are also just objects in Ruby, you can also define an instance variable on class level (or more correctly: on the singleton class of your class). This can work like this:
class Foo
def self.bar
#bar
end
def self.bar=(value)
#bar = value
end
end
Compared to class variables, these instance variables on the singleton class are not accessible on Foo instances nor on child classes of Foo.

The ##bar will return the same variable to all instances of the class, not just the same variable to all methods in the class.
The way I think of class variables (##variables) is as namespaced global variables. Their usage is just about as frowned upon as using global variables, but not quite since you are limiting the scope to within the code defined in your class.
Generally they would be used to track some kind of state across your application.
Let's say you had an object that needed to be able to identify its most recently instantiated sibling object.
One way to do that would be via a global variable:
class MyThing
def initialize
$latest_thing = self
end
def latest
$latest_thing
end
end
thing1 = MyThing.new
thing1.latest # => thing1
thing2 = MyThing.new
thing1.latest # => thing2
thing2.latest # => thing2
Now, that uses a global variable which is generally perceived as bad practice, one of the reasons being for pollution of the global namespace and risk of naming collision and/or someone else changing it.
If you are dealing with a situation like this where you need this shared state between instances, but no one outside needs to know about it, then you can use the class variable exactly like a global:
class MyThing
def initialize
##latest_thing = self
end
def latest
##latest_thing
end
end
thing1 = MyThing.new
thing1.latest # => thing1
thing2 = MyThing.new
thing1.latest # => thing2
thing2.latest # => thing2
That's just generally cleaner/safer/better encapsulated, since any 3rd party code can not simply do ##latest_thing = :something_else the way that they could do had a global been used.
Hope that helps. I think class variables are rarely used or encouraged in the wild, but on the rare occasion I've needed to use one it was for things like this.

Related

What does instance variable that looks like this #my_variable inside a self.method mean?

I dont understand what an instance variable inside a class method does. Below code makes no sense to me. How can a class method manipulate an instance variable? I can call a class method without even having an instance.
def self.schema
return #schema if #schema
DB.table_info(table) do |row|
#schema[row['name']] = row['type']
#schema
end
Edit: follow up question after #Aetherus's answer.
What is first_name in the below code example? Why cant i access it as a class variable since it is inside class scope? Why does all 3 methods give me errors?
class Person
#class scope
first_name = "jimmy"
# expected error beacuse it would treat as local variable
def print_name
#instance scope
first_name
end
#to my understanding this should work, but it doesnt. i dont know why
def print_name_2
#instance scope
#with self.class i should be able to access class scope?
self.class.first_name
end
#to my understading this should work, but it doesnt. I dont know why.
def self.print_name
#class scope
#inside class scope, i should able to access first_name?
first_name
end
end
In short, these instance variables belong to the class, not the instances of that class.
To understand it, you need to know more about Ruby.
Classes are objects
In Ruby, all the classes are just objects of type Class.
String.class #=> Class
Array.class #=> Class
Class.class #=> Class
And you can define anonymous classes by instantiating Class
foo = Class.new do
# Here you can define methods
end
foo.new #=> an instance of an anonymous class
Because classes are objects, they can have instance variables too.
Gate of scopes
There are 4 keywords that triggers scope switching: module, class, def and do (for blocks). Here I only show the class and def.
# in the scope of main
class Foo
# in the scope of Foo
def self.bar
# still in the scope of Foo
end
# in the scope of Foo
def bar
# in the scope of an instance of Foo
end
# back to the scope of Foo again
end
# back to the scope of main
The instance variables defined in a scope belongs to the current object (a.k.a. self) of that scope. In the previous example, if you define a instance variable in the scope of Foo, that instance variable belongs to the self of that scope, which is the class Foo.

Local variables in `class` definition scope versus `def` method scope

Here, I create a local variable in class scope:
class MyClass
x = 1
puts x
end
It prints 1 even if I don't create any instances of MyClass.
I want to use x in some method:
class MyClass
x = 1
def method
puts x
end
end
m = MyClass.new
m.method
And I can't. Why? I get that class definition creates a scope, but why is it not accessible in the method? Isn't scope of the method inside the scope of the class?
I can imagine that this is related to creation of a class. Since any class is an object of Class, maybe the scope of MyClass is the scope of some Class method, and the way of coupling methods of MyClass to that instance makes their scope completely different.
It also seems to me that I can't just create a scope with {} (like in C) or something like do..end. Am I correct?
Scope of a method is not inside the class. Each method has its own entirely new scope.
New scopes are created whenever you use the class, module, and def keywords. Using brackets, as in C, does not create a new scope, and in fact you cannot arbitrarily group lines of code using brackets. The brackets (or do...end) around a Ruby block create a block-level scope, where variables previously created in the surrounding scope are available, but variables created within the block scope do not escape into the surrounding scope afterward.
Instance methods share the scope of their instance variables with other instances methods. An instance variable defined in the scope of a class definition is available in class-level singleton methods, but not in instance methods of the class.
Illustration:
class Foo
x = 1 # available only here
#y = 2 # class-wide value
def self.class_x
#x # never set; nil value
end
def self.class_y
#y # class-wide value
end
def initialize(z)
x = 3 # available only here
#z = z # value for this instance only
end
def instance_x
#x # never set; nil
end
def instance_y
#y # never set; nil
end
def instance_z
#z # value for this instance only
end
end
Foo.class_x # => nil
Foo.class_y # => 2
Foo.new(0).instance_x # => nil
Foo.new(0).instance_y # => nil
foo3 = Foo.new(3)
foo4 = Foo.new(4)
foo3.instance_z # => 3
foo4.instance_z # => 4
You can access class-level instance variables from within instances using the class-level getter. Continuing the example above:
class Foo
def get_class_y
self.class.class_y
end
end
foo = Foo.new(0)
foo.get_class_y # => 2
There exists in Ruby the notion of a "class variable," which uses the ## sigil. In practice, there is almost never a reasonable use case for this language construct. Typically the goal can be better achieved using a class-level instance variable, as shown here.
Here, I create a local variable in class scope:
class MyClass
x = 1
puts x
end
It prints 1 even if I don't create any instances of MyClass.
Correct. The class definition body is executed when it is read. It's just code like any other code, there is nothing special about class definition bodies.
Ask yourself: how would methods like attr_reader/attr_writer/attr_accessor, alias_method, public/protected/private work otherwise? Heck, how would def work otherwise if it didn't get executed when the class is defined? (After all, def is just an expression like any other expression!)
That's why you can do stuff like this:
class FileReader
if operating_system == :windows
def blah; end
else
def blubb; end
end
end
I want to use x in some method:
class MyClass
x = 1
def method
puts x
end
end
m = MyClass.new
m.method
And I can't. Why? I get that class definition creates a scope, but why is it not accessible in the method? Isn't scope of the method inside the scope of the class?
No, it is not. There are 4 scopes in Ruby: script scope, module/class definition scope, method definition scope, and block/lambda scope. Only blocks/lambdas nest, all the others create new scopes.
I can imagine that this is related to creation of a class. Since any class is an object of Class, maybe the scope of MyClass is the scope of some Class method, and the way of coupling methods of MyClass to that instance makes their scope completely different.
Honestly, I don't fully understand what you are saying, but no, class definition scope is not method definition scope, class definition scope is class definition scope, and method definition scope is method definition scope.
It also seems to me that I can't just create a scope with {} (like in C) or something like do..end. Am I correct?
Like I said above: there are 4 scopes in Ruby. There is nothing like block scope in C. (The Ruby concept of "block" is something completely different than the C concept of "block.") The closest thing you can get is a JavaScript-inspired immediately-invoked lambda-literal, something like this:
foo = 1
-> {
bar = 2
foo + bar
}.()
# => 3
bar
# NameError
In general, that is not necessary in Ruby. In well-factored code, methods will be so small, that keeping track of local variables and their scopes and lifetimes is really not a big deal.
So just creating a class without any instances will lead to something
actually executing in runtime (even allocating may be)? That is very
not like C++. –
Check out this code:
Dog = Class.new do
attr_accessor :name
def initialize(name)
#name = name
end
end
If you execute that code, there won't be any output, but something still happened. For instance, a global variable named Dog was created, and it has a value. Here's the proof:
Dog = Class.new do
attr_accessor :name
def initialize(name)
#name = name
end
end
dog = Dog.new("Ralph")
puts dog.name
--output:--
Ralph
The assignment to the Dog constant above is equivalent to writing:
class Dog
...
...
end
And, in fact, ruby steps through each line inside the class definition and executes each line--unless the line of code is inside a def. The def is created but the code inside a def doesn't execute until the def is called.
A very common line you will see inside a class definition is:
attr_accessor :name
...which can be rewritten as:
attr_accessor(:name)
...which makes it obvious that it's a method call. Ruby executes that line--and calls the method--when you run a file containing the class definition. The attr_accessor method then dynamically creates and inserts a getter and a setter method into the class. At runtime. Yeah, this ain't C++ land anymore--welcome to NeverNever Land.
I get that class definition creates a scope, but why is it not
accessible in the method?
Because that is the way Matz decided things should be: a def creates a new scope, blocking visibility of variables outside the def. However, there are ways to open up the scope gates, so to speak: blocks can see the variables defined in the surrounding scope. Check out define_method():
class MyClass
x = 1
define_method(:do_stuff) do
puts x
end
end
m = MyClass.new
m.do_stuff
--output:--
1
The block is everything between do...end. In ruby, a block is a closure, which means that when a block is created, it captures the variables in the surrounding scope, and carries those variables with it until the the block is executed. A block is like an anonymous function, which gets passed to a method as an argument.
Note that if you use the Class.new trick, you can open two scope gates:
x = 1
MyClass = Class.new do
define_method(:do_stuff) do
puts x
end
end
m = MyClass.new
m.do_stuff
--output:--
1
Generally, ruby allows a programmer to do whatever they want, rules be damned.

Preventing conflict with module-specific instance variables

I have a mixin that can show up in several different areas of our codebase. In a couple of cases there is, or was, an edge case where the module's use of instance variables conflicted with instance variables used by the classes.
Prepending variable names #__like_this was one solution, but the other we came up with was more sophisticated, having this general structure, in which the accessor methods are closures:
module HiddenValue
def initialize
hidden_value = nil
define_singleton_method :value, ->() { hidden_value }
define_singleton_method :value=, ->(v) { hidden_value = v }
super
end
end
class RealClass
include HiddenValue
# [...]
end
foo = RealClass.new
foo.value = 123
foo.value # => 123
Is this bad style? It means that all methods wanting direct access to the variable must be defined dynamically inside initialize, and that could get ugly. Is there a cleaner way? Or is this the closest we'll get to a module-level "lexical"-ish scoped instance variable?

Should I use class variables or class-instance variables for class static variables in Ruby?

class Something
##variable = 'Class variable'
def give_me
##variable
end
end
class OtherThing
#variable = 'Instance variable with an interface'
class << self
attr_accessor :variable
end
def give_me
self.class.variable
end
end
p Something.new.give_me
p OtherThing.new.give_me
What I want to know is, which one should I use?
Which are the benefits and cons of each?
Class variables are:
Private unless you make an interface
Shared between inheritances
Shorter to write
Class-instance variables are:
Public, since you must use an interface to access them
Not shared between inheritances, but are set to nil when inherited
Longer to write
What else should I have in mind?
I recently discovered ActiveSupport defines class_inheritable_accessor, which does what the class-instance variables do with the advantage that objects are not shared across inheritance, and you can have a default value for the variable when subclassing.
class Foo
class_inheritable_accessor :x, :y
end
Foo.x = 1
class Bar < Foo
end
Bar.x #=> 1
Bar.x = 3
Bar.x #=> 3
Foo.x #=> 1
More info here
Just for completeness: of the two presented options, I prefer going with the class-instance variables, since is often the expected behavior.
Never use class variables in Ruby, ever. They cause problems with inheritance. Always use class instance variables instead.
You also have the option of declaring instance variables at the class level:
class Foo
#bar = 'baz'
def Foo.print
puts #bar
end
end
Overall, I'd avoid class variables, as the shared-across-inheritance model is often very surprising and non-obvious; to be honest, I'm not sure what utility they really offer, other than being a not-quite-global-global.
If you need a 'scoped' global variable, I'd go for class-level instance variables with accessors. You avoid the inheritance 'surprise', while still maintaining encapsulation.
Class instance variables are generally more useful and less surprising than class variables, so you should probably use them.
And now I shall spell some things out in the excruciating detail you've come to expect from a Ruby answer on StackOverflow:
To declare or refer to a class instance variable, you need to be in class scope and use a single # sign. This places the variable on the singleton class instance for that class.
Unfortunately, when you're in class scope and use the def keyword, your methods are placed on the list of instance methods for that class, and are executed in instance scope, so their #-sign variables will be on the instance they're in.
What we want instead is to define methods on the class, not on its instances. What that really means is that these methods are on the list of instance methods for the singleton class of the class object. (Phew!)
So, to sum up: There are at least four idioms for switching over and defining methods on the singleton class of the class object Foo:
class Foo
#a, #b, #c, #d = 1, 2, 3, 4
# 1. pass the target to def
def Foo.a
#a
end
# 2. pass the target to def, relying on the fact that self
# happens to be the class object right now
def self.b
#b
end
# switch from class scope to singleton class scope
class << self
# 3. define a plain accessor in singleton class scope
def c
#c
end
# 4. use a macro to define an accessor
attr_reader :d
end
end
p [Foo.a, Foo.b, Foo.c, Foo.d]
#=> [1, 2, 3, 4]
(There are probably half a dozen more ways to do this, once you factor in class_eval and define_method and the like, but that should satisfy you for now. :-))
One final note: class instance variables are only available via the class they're defined on. If you try to call any of those methods from (or via) a subclass, the methods will execute, but the # variables will all be nil, since self will be the subclass's class object, not the parent class' class object.
class Bar < Foo
end
p [Bar.a, Bar.b, Bar.c, Bar.d]
#=> [nil, nil, nil, nil]

Class Variables

Explain please, I can not understand.
class Foo
#a = 123
##b = 123
end
What are the advantages of variable objects-classes and the class variables? When should I use first, and in which the second?
Instance level variables area created anew for each instance of the class. For example, a variable #id should probably be unique for each instance of Foo. However, there may be some values that should be the same for every instance of the type. In that case, a class variable would be more appropriate.
One important side effect of class level variables is that they are shared amongst derived classes as well. This means that changing the value in a subclass of 'Foo' will change it for 'Foo' objects as well. This may be what you want, but it can be a bit surprising to find out the hard way.
For example:
class Foo
##some_var = 1
def bar
puts(##some_var)
end
end
class Baz < Foo
def perhaps_unexpected
##some_var = 10
Foo.new.bar #prints '10'
end
end
Use a class variable when you want all the instances of the class to share that variable, and use an instance variable when you want each instance to have its own non-shared variable.

Resources