Constants or class variables in ruby? - ruby

I've been programming in Ruby for a few months now, and I'm wondering when it is appropriate to use constants over class variables and vice versa. (I'm working in Rails, thinking about constants in models).
class Category
TYPES = %w(listing event business).freeze
end
OR
class Category
##types = %w(listing event business).freeze
cattr_reader :types
end
Are there circumstances where one is preferable to another? Or is it just a matter of taste/style?

The main thing is that by using the CONSTANT notation, you're making it clear to the reader. the lower case, frozen string gives the impression is might be settable, forcing someone to go back and read the RDoc.

If these are really constant values that you define in source code and do not want to change during code execution then I would recommend to use constant.
If you plan to set and/or change these values dynamically during execution then use class variable with getters and setters.

Basically, you could put it like this: If you want something that's constant, use a constant. If you want something that's variable, use a variable. It seems like your list of types are constants, seeing it is a frozen array, so I would say it makes sense to use a constant in this case.

Note that class variables are private to a class and its instances (cf. http://phrogz.net/programmingruby/tut_classes.html). However, if you want to make your constant private you can always do:
FOO = 18
private_constant :FOO

If you don't want the value to ever change during the runtime of your program, and you are comfortable with allowing the value to be accessed outside of your class, use a constant.
Otherwise, you can use a class variable. However, be aware that class variables are shared among subclasses and instances of subclasses. So if you might at some point in the future implement a child class, you have to be very careful about your use of class variables.
Refer to the answers here for more on this: Class variables in Ruby

Related

using the ## with instance variables in ruby [duplicate]

Ruby has 5 variable scopes:
Local Variables: these are the normal variables, example x = 25, y = gaurish where x and y are local variables.
Instance Variables: these are denoted with # symbol infront of the actual variable name. mainly used with classes, so that each instance/object of the class has a different/separate value. example. #employee.name = 'Alex'
Class Variables: denoted with ## symbols in front of variable name. class variable, I think have same value accos all instances/object.
Global variables: they start with $ symbol and are accessible everywhere. example $LOAD_PATH
Constants: Must start with Capital letter but by convention written in ALL_CAPS. although, it is a constant but its value its not constant and can be changed(ruby will throw a warning, though). so in the sense, this also acts like a variable.
As you may notice,all of the above are variables which store some value of some type and their value can be changed. But, each scope does something little bit different. Having 5 different types of variable scopes is confuses hell out of me. Mainly, I have difficulty deciding under what case, I should be using a particular scope in my code. so I have some questions in my mind. please answer:
I notice that local variables and class variables stay same for all objects/instances, unlike instance variables. so what difference between Local variables and Class variables?
Can local variables be used in place of class variables? or vice-versa. And if yes, then why, and if no, then why not?
Global variables in ruby remind me of the evil global $x variables in PHP. Are global variables in ruby also considered evil and therefore should not be used. OR, there are specific cases where it makes sense to use global variables in ruby?
Why constants are not constants and allow their value to be changed? A constant's value by definition should be constant right? else, we can just use another variable and don't change its value. would that be equivalent to a CONSTANT in ruby?
Any page/resource/link which explains the difference between 5 different variable scopes in ruby? I like to keep one handy for reference.
Under what use-case, I should be using a particular variable scope in my code. so one would explain all 5 cases with can example that would be cool, this is my main reason for confusion.
is there a de facto choice like public in java? Which would be the safe bet in most use-cases?
Thanks for taking time to read and answer question
Class variables are the same for all instances, because they're class variables–associated with the class. Everything access the same variable, including each instance.
No. Local variables are just that–local. They may be local to a function, or local to the class declaration, which is different than being a class variable. Locals in a class declaration go out of scope when the class declaration ends.
That's because they're exactly the same–they're global. Global state is always evil; this is not a property of the language or environment. That said, some global state may be required–that's just the way it is. It makes sense to use global state when there's global state. The trick is to use global state properly, which is sometimes a non-trivial endeavor.
That's just how Ruby is.
One has already been given by Chris.
I would think this question would be largely self-answering. Global when the entire world needs access. Instance when it's specific to a class instance. Local when it's only required in a local scope (e.g., a method, a block (note differences between 1.8 and 1.9 with regard to block scope), etc.) Constant when the variable isn't supposed to change. A class variable when it's something that either every instance needs, or if exposed via a class method, something tightly associated with a class.
There is no "most use-cases", it totally depends on what you're doing with the variable. And public isn't the de facto choice in Java–it depends on the entity in question. Default Java scope is package-private (methods, properties). Which to use in Ruby depends entirely upon the use-case, noting that as with Java, and even more easily in Ruby, things can be circumvented.
Local variables are not equivalent to class ones, they are tied to the block you are in. Any local declared in a block can be used there. Class variables are tied to the class structure you are in. Defining a class is itself a block, so you might be able to access local variables similarly, but you'll find if you refer to your class in a different context you cannot refer to the local variable in the same fashion.
Global variables are considered bad form, if abused. OOP should help you structure your programs such that constants on the entire program aren't needed. Think of them as actually being global: if you can't vouch for its consistency to the entire world, like the value of PI or whether or not you love your wife, you probably shouldn't be making promises.
Once you get the hang of them, I find "Ruby Variable Scope" to be a good reference.
I found a good and in-depth explanation regarding different scopes and their visibilities in Ruby in the following link .Scopes and Visibilities with Examples in detail.
According to it ,
Class variable (##a_variable): Available from the class definition and any sub-classes. Not available from anywhere outside.
Instance variable (#a_variable): Available only within a specific object, across all methods in a class instance. Not available directly from class definitions.
Global variable ($a_variable): Available everywhere within your Ruby script.
Local variable (a_variable): It is available only in the particular method or block in ruby script.
Some more explanation regarding Instance variables is : You can access instance variables in any method of that particular class. While local variables can't be accessed outside of the method. Below is an example from ruby monk which explains this concept thoroughly.
class Item
def initialize(item_name, quantity)
#item_name = item_name
#quantity = quantity
end
def show
puts #item_name
puts #quantity
supplier = "Acme corp"
puts supplier
end
end
Item.new("tv",1).show
Here supplier is a local variable which can be accessed from show method only in our example.Just try to declare the supplier variable in the initialize method and printing it out in show method. It will give an error as undefined variable supplier.
i hope it helps. :)
Here is my two cents for this and is writing for c++/java/c# programmers:
A Ruby local/$Global variable is a bit like c++/java/c#'s local/Global variable.
A Ruby #instance variable it's like c++/java/c#'s member variable /class property which can be accessible in any member function/class method.Though Ruby instance can be applied not only to class but also to Ruby Module.
A Ruby ##class variable is like as c++/java's static member variable which is share between all instances of the same class.

When to use constants instead of instance variables in Ruby?

I understand that instance variables are mean to be states, and constants are meant to be constant. Is there any reason (besides convention) to use a constant instead of an instance variable? Is there a memory/speed advantage to using constants?
There's a few things to consider here:
Will the value change within the life-cycle of an object?
Will you need to override the value in sub-classes?
Do you need to configure the value at run-time?
The best kind of constants are those that don't really change short of updating the software:
class ExampleClass
STATES = %i[
off
on
broken
].freeze
end
Generally you use these constants internally in the class and avoid sharing them. When you share them you're limited in how they're used. For example, if another class referenced ExampleClass::STATES then you can't change that structure without changing other code.
You can make this more abstract by providing an interface:
class ExampleClass
def self.states
STATES
end
end
If you change the structure of that constant in the future you can always preserve the old behaviour:
class ExampleClass
STATES = {
on: 'On',
off: 'Off',
broken: 'Broken'
}.freeze
def self.states
STATES.keys
end
end
When you're talking about instance variables you mean things you can configure:
class ConfigurableClass
INITIAL_STATE_DEFAULT = :off
def self.initial_state
#initial_state || INITIAL_STATE_DEFAULT
end
def self.initial_state=(value)
#initial_state = value ? value.to_sym
end
end
Constants are great in that they're defined once and used for the duration of the process, so technically they're faster. Instance variables are still pretty quick, and are often a necessity as illustrated above.
Constants, unlike instance variables, are global. And they will at least complain if you try to re-assign their value.
While there might be a theoretical difference in memory/speed, it will be irrelevant in practice.
You may not realize this, but classes and modules are considered constants.
pry(main)> Foo
NameError: uninitialized constant Foo
The best advice I can give as to when you should use constants are when they are exactly that, constant. For example, if I was making a scope in rails to find all the of recent Foos for instance, I would create a constant that shows what recent is.
class Foo < ActiveRecord::Base
DAYS_TILL_OLD = 7.days
scope :recent, -> { where "created_at > ?", DateTime.now - DAYS_TILL_OLD }
end

How to use an object's instance variables in const_missing(), threadsafe?

I want to treat certain uppercase identifiers as dynamically calculated constants - so when I evaluate a code string such as eval("foo(BAR)") I can look up the value of BAR and supply it to the evaluation.
Don't even ask why I want to do this. :-)
The trouble is that const_missing() (unlike, say, method_missing() ) must be a class method, not an instance method. So if I try to write a function like this:
def self.const_missing(name)
if #data[name]
return #data[name]
end
raise "Missing const #{name.inspect}"
end
I can't see the instance variable #data that tells me what the value of FOO should be.
I could of course use a class variable ##data, but that would not let me a different data for each object. I could set ##data from #data immediately before doing the eval, but that would not be thread-safe nor recursion-friendly.
My fallback is to use thread-local storage to contain a stack of #data, and push and pop #data before and after the eval call. But that feels so... inelegant.
Is there a better way to do this?
Don't even ask why I want to do this. :-)
thx for the suggestion, but why exactly are you doing this?
i'm asking because there probably is a different approach that people can show you if you try to explain the problem you are trying to solve.
another thing, don't ever use eval. just don't! if you are not able to one of the other possible metaprogramming methods like class_eval instance_eval method_missing and friends, you are probably doing it wrong.
let me emphasize, DONT USE eval()!

Difference between various variables scopes in ruby

Ruby has 5 variable scopes:
Local Variables: these are the normal variables, example x = 25, y = gaurish where x and y are local variables.
Instance Variables: these are denoted with # symbol infront of the actual variable name. mainly used with classes, so that each instance/object of the class has a different/separate value. example. #employee.name = 'Alex'
Class Variables: denoted with ## symbols in front of variable name. class variable, I think have same value accos all instances/object.
Global variables: they start with $ symbol and are accessible everywhere. example $LOAD_PATH
Constants: Must start with Capital letter but by convention written in ALL_CAPS. although, it is a constant but its value its not constant and can be changed(ruby will throw a warning, though). so in the sense, this also acts like a variable.
As you may notice,all of the above are variables which store some value of some type and their value can be changed. But, each scope does something little bit different. Having 5 different types of variable scopes is confuses hell out of me. Mainly, I have difficulty deciding under what case, I should be using a particular scope in my code. so I have some questions in my mind. please answer:
I notice that local variables and class variables stay same for all objects/instances, unlike instance variables. so what difference between Local variables and Class variables?
Can local variables be used in place of class variables? or vice-versa. And if yes, then why, and if no, then why not?
Global variables in ruby remind me of the evil global $x variables in PHP. Are global variables in ruby also considered evil and therefore should not be used. OR, there are specific cases where it makes sense to use global variables in ruby?
Why constants are not constants and allow their value to be changed? A constant's value by definition should be constant right? else, we can just use another variable and don't change its value. would that be equivalent to a CONSTANT in ruby?
Any page/resource/link which explains the difference between 5 different variable scopes in ruby? I like to keep one handy for reference.
Under what use-case, I should be using a particular variable scope in my code. so one would explain all 5 cases with can example that would be cool, this is my main reason for confusion.
is there a de facto choice like public in java? Which would be the safe bet in most use-cases?
Thanks for taking time to read and answer question
Class variables are the same for all instances, because they're class variables–associated with the class. Everything access the same variable, including each instance.
No. Local variables are just that–local. They may be local to a function, or local to the class declaration, which is different than being a class variable. Locals in a class declaration go out of scope when the class declaration ends.
That's because they're exactly the same–they're global. Global state is always evil; this is not a property of the language or environment. That said, some global state may be required–that's just the way it is. It makes sense to use global state when there's global state. The trick is to use global state properly, which is sometimes a non-trivial endeavor.
That's just how Ruby is.
One has already been given by Chris.
I would think this question would be largely self-answering. Global when the entire world needs access. Instance when it's specific to a class instance. Local when it's only required in a local scope (e.g., a method, a block (note differences between 1.8 and 1.9 with regard to block scope), etc.) Constant when the variable isn't supposed to change. A class variable when it's something that either every instance needs, or if exposed via a class method, something tightly associated with a class.
There is no "most use-cases", it totally depends on what you're doing with the variable. And public isn't the de facto choice in Java–it depends on the entity in question. Default Java scope is package-private (methods, properties). Which to use in Ruby depends entirely upon the use-case, noting that as with Java, and even more easily in Ruby, things can be circumvented.
Local variables are not equivalent to class ones, they are tied to the block you are in. Any local declared in a block can be used there. Class variables are tied to the class structure you are in. Defining a class is itself a block, so you might be able to access local variables similarly, but you'll find if you refer to your class in a different context you cannot refer to the local variable in the same fashion.
Global variables are considered bad form, if abused. OOP should help you structure your programs such that constants on the entire program aren't needed. Think of them as actually being global: if you can't vouch for its consistency to the entire world, like the value of PI or whether or not you love your wife, you probably shouldn't be making promises.
Once you get the hang of them, I find "Ruby Variable Scope" to be a good reference.
I found a good and in-depth explanation regarding different scopes and their visibilities in Ruby in the following link .Scopes and Visibilities with Examples in detail.
According to it ,
Class variable (##a_variable): Available from the class definition and any sub-classes. Not available from anywhere outside.
Instance variable (#a_variable): Available only within a specific object, across all methods in a class instance. Not available directly from class definitions.
Global variable ($a_variable): Available everywhere within your Ruby script.
Local variable (a_variable): It is available only in the particular method or block in ruby script.
Some more explanation regarding Instance variables is : You can access instance variables in any method of that particular class. While local variables can't be accessed outside of the method. Below is an example from ruby monk which explains this concept thoroughly.
class Item
def initialize(item_name, quantity)
#item_name = item_name
#quantity = quantity
end
def show
puts #item_name
puts #quantity
supplier = "Acme corp"
puts supplier
end
end
Item.new("tv",1).show
Here supplier is a local variable which can be accessed from show method only in our example.Just try to declare the supplier variable in the initialize method and printing it out in show method. It will give an error as undefined variable supplier.
i hope it helps. :)
Here is my two cents for this and is writing for c++/java/c# programmers:
A Ruby local/$Global variable is a bit like c++/java/c#'s local/Global variable.
A Ruby #instance variable it's like c++/java/c#'s member variable /class property which can be accessible in any member function/class method.Though Ruby instance can be applied not only to class but also to Ruby Module.
A Ruby ##class variable is like as c++/java's static member variable which is share between all instances of the same class.

Using Instance Variables in Class Methods - Ruby

I have a class something like below, and I used instance variables (array) to avoid using lots of method parameters.
It works as I expected but is that a good practice?
Actually I wouldn't expect that worked, but I guess class methods are not working as static methods in other languages.
class DummyClass
def self.dummy_method1
#arr = []
# Play with that array
end
def self.dummy_method2
# use #arr for something else
end
end
The reason instance variables work on classes in Ruby is that Ruby classes are instances themselves (instances of class Class). Try it for yourself by inspecting DummyClass.class. There are no "static methods" in the C# sense in Ruby because every method is defined on (or inherited into) some instance and invoked on some instance. Accordingly, they can access whatever instance variables happen to be available on the callee.
Since DummyClass is an instance, it can have its own instance variables just fine. You can even access those instance variables so long as you have a reference to the class (which should be always because class names are constants). At any point, you would be able to call ::DummyClass.instance_variable_get(:#arr) and get the current value of that instance variable.
As for whether it's a good thing to do, it depends on the methods.
If #arr is logically the "state" of the instance/class DummyClass, then store it in instance variable. If #arr is only being used in dummy_method2 as an operational shortcut, then pass it as an argument. To give an example where the instance variable approach is used, consider ActiveRecord in Rails. It allows you to do this:
u = User.new
u.name = "foobar"
u.save
Here, the name that has been assigned to the user is data that is legitimately on the user. If, before the #save call, one were to ask "what is the name of the user at this point", you would answer "foobar". If you dig far enough into the internals (you'll dig very far and into a lot of metaprogramming, you'll find that they use instance variables for exactly this).
The example I've used contains two separate public invocations. To see a case where instance variables are still used despite only one call being made, look at the ActiveRecord implementation of #update_attributes. The method body is simply load(attributes, false) && save. Why does #save not get passed any arguments (like the new name) even though it is going to be in the body of save where something like UPDATE users SET name='foobar' WHERE id=1;? It's because stuff like the name is information that belongs on the instance.
Conversely, we can look at a case where instance variables would make no sense to use. Look at the implementation of #link_to_if, a method that accepts a boolean-ish argument (usually an expression in the source code) alongside arguments that are ordinarily accepted by #link_to such as the URL to link to. When the boolean condition is truthy, it needs to pass the rest of the arguments to #link_to and invoke it. It wouldn't make much sense to assign instance variables here because you would not say that the invoking context here (the renderer) contains that information in the instance. The renderer itself does not have a "URL to link to", and consequently, it should not be buried in an instance variable.
Those are class instance variables and are a perfectly legitimate things in ruby: classes are objects too (instances of Class) and so have instance variables.
One thing to look out for is that each subclass will have its own set of class instance variables (after all these are different objects): If you subclassed DummyClass, class methods on the subclass would not be able to see #arr.
Class variables (##foo) are of course the other way round: the entire class hierarchy shares the same class variables.

Resources