I am very new to ruby (I'm actually c# dev.), so this question might be a noob one.
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 to do?
Actually I wouldn't expect that worked, but I guess class methods are not working as static methods in other languages, so I am wondering if that is a good practice or if I may face problems such as acting those variables as class variables and messing everything up.
@arr = 
# Play with that array
# use @arr for something else
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.
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.
@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
Class variables (
@@foo) are of course the other way round: the entire class hierarchy shares the same class variables.