Normal Variables Vs Instance variable in Ruby, Whats the difference?
A normal variable has scope only within the current context; an instance variable has scope throughout one instance of a class. In your case they're confused because the context is main
, which acts as an instance of Object
.
Consider the following, which may make things clearer
class User
def set_name
@name = "Bob"
surname = "Cratchett"
end
def hi
puts "Hello, " + @name
end
def hello
puts "Hello, Mr " + surname
end
end
irb(main):022:0> u = User.new
=> #<User:0x29cbfb0>
irb(main):023:0> u.set_name
irb(main):024:0> u.hi
Hello, Bob
=> nil
irb(main):025:0> u.hello
NameError: undefined local variable or method `surname' for #<User:0x29cbfb0 @name="Bob">
Difference between class variables and class instance variables?
A class variable (@@
) is shared among the class and all of its descendants. A class instance variable (@
) is not shared by the class's descendants.
Class variable (@@
)
Let's have a class Foo with a class variable @@i
, and accessors for reading and writing @@i
:
class Foo
@@i = 1
def self.i
@@i
end
def self.i=(value)
@@i = value
end
end
And a derived class:
class Bar < Foo
end
We see that Foo and Bar have the same value for @@i
:
p Foo.i # => 1
p Bar.i # => 1
And changing @@i
in one changes it in both:
Bar.i = 2
p Foo.i # => 2
p Bar.i # => 2
Class instance variable (@
)
Let's make a simple class with a class instance variable @i
and accessors for reading and writing @i
:
class Foo
@i = 1
def self.i
@i
end
def self.i=(value)
@i = value
end
end
And a derived class:
class Bar < Foo
end
We see that although Bar inherits the accessors for @i
, it does not inherit @i
itself:
p Foo.i # => 1
p Bar.i # => nil
We can set Bar's @i
without affecting Foo's @i
:
Bar.i = 2
p Foo.i # => 1
p Bar.i # => 2
What is the difference between using local variable or instance variable in an Rails API?
The performance difference will be negligible.
But there's two competing guidelines at work. One is "Always use the weakest construction." Don't use double "quotes" if you can use single 'quotes'. Don't use a regular expression if you can use String#index. Don't use an instance variable if you can use a local variable.
The other guideline is "Design for testing." If you use an instance variable, your test can inspect it with assigns(:user)
. That rule trumps the "weakest construction" rule. So use an instance variable, and write lots of automated tests!
Difference between various variables scopes in ruby
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.
Difference between local and instance variables
instance variables exist as long as the class exists
They exist as long as the object exist. Instance variables are per-object, not per-class.
what happens if you declare a local variable in the class scope without prefixing it with @?
Then the variable is in scope within the class definition, but not within any def
s inside that class definition as those introduce a new scope.
Doesn't that implicitly make it an instance variable, even though you didn't use an @ to declare it as one?
No.
If you use define_method
instead of def
to create methods, the local variable will be accessible within the methods, but since the variable only exists once (not once per object), they'd act more like class variables than instance variables in that case. I also can't think of a good reason why you'd use them that way.
difference between class method , instance method , instance variable , class variable?
First take a look at this diagram:
You can rightly say that “obj has a method called my_method( ),” meaning that you’re able to call obj.my_method(). By contrast, you shouldn’t say that “MyClass has a method named my_method().” That would be confusing, because it would imply that you’re able to call MyClass.my_method() as if it were a class method.
To remove the ambiguity, you should say that my_method() is an instance method (not just “a method”) of MyClass, meaning that it’s defined in MyClass, and you actually need an instance of MyClass to call it. It’s the same method, but when you talk about the class, you call it an instance method, and when you talk about the object, you simply call it a method. Remember this distinction, and you won’t get confused when writing introspective code like this:
String.instance_methods == "abc".methods # => true String.methods == "abc".methods # => false
an object’s instance variables live in the object itself, and an object’s methods live in the object’s class. That’s why objects of the same class share methods but don’t share instance variables.
Ruby Instance Variables or Local Variables?
I try to explain it with a little example:
class MyClass
def meth
conn = 1
end
def result
conn
end
end
x = MyClass.new
p x.result #-> test.rb:6:in `result': undefined local variable or method `conn'
conn
is unknown. Let's try to call meth
before:
class MyClass
def meth
conn = 1
end
def result
conn
end
end
x = MyClass.new
x.meth # try to create conn
p x.result #-> test.rb:6:in `result': undefined local variable or method `conn'
Same result. So conn
is no instance variable. You define a local variable in meth
but it is unknown outside.
Let's try the same with instance variables:
class MyClass
def meth
@conn = 1
end
def result
@conn
end
end
x = MyClass.new
p x.result #-> nil (no value assigned (*), but is is existing)
x.meth # initialze @conn with a value
p x.result #-> 1
With the usage of accessor-methods you define implicit an instance variable:
class MyClass
attr_reader :conn
def meth
conn = 1
end
def result
conn
end
end
x = MyClass.new
p x.result #-> nil (no value assigned (*), but is is existing)
x.meth # define conn with a value
p x.result #-> nil - the instance variable is not changed, a locale variable was used
In method result
the conn
is the reader method conn
. In the method meth
it is a locale variable (this can be confusing, because now you have a variable with the same name as a variable.
If you want to change the conn
-value in the meth
-method you must define a setter and use self.conn
:
class MyClass
attr_reader :conn
attr_writer :conn
def meth
self.conn = 1
end
def result
conn
end
end
x = MyClass.new
p x.result #-> nil (not defined yet, but is is existing)
x.meth # define conn with a value
p x.result #-> 1
You can replace attr_reader
and attr_writer
with attr_accessor
.
(*) Remark: I wrote no value assigned - this is not really correct, nil
is also a value.
In what circumstances should I use instance variables instead of other variable types?
In general an instance variable is local and persisted inside an instance of an object, whereas a local variable is only local and persisted inside a function/object/block scope. For instance:
class User
def name
@name
end
def name= name
@name = name
end
end
def greet user
name = user.name || 'John'
p "Hi, my name is #{name}"
end
user = User.new
greet user
=> 'Hi, my name is John'
name
=> NameError: undefined local variable or method 'name' for main:Object
user.name = "Mike"
greet user
=> 'Hi, my name is Mike'
@name
=> nil
In the greet function name
is a local variable that is only defined within that function. The name variable is set on the first line on the function, name = user.name || 'John'
, but its value is not persisted outside of the function. When you try calling name
you get a NameError
because name has only been defined as a local variable within the greet function.
@name
is local to the user instance of the User class. When you try calling it outside of that context you get nil
. This is one difference between local and instance variables, instance variables return nil if they have not been defined, whereas local non-instance variables raise an Error.
Notice that both variable types are local to a specific context though. @name
is defined within the user instance, so when you call user.name
you are calling the name function in the user instance, in which @name
is defined. name
is only defined in the greet function, so when you call p "Hi, my name is #{name}"
you are able to get a value for name
because you are within the scope in which it is defined.
Ruby class instance variable vs. class variable
Instance variable on a class:
class Parent
@things = []
def self.things
@things
end
def things
self.class.things
end
end
class Child < Parent
@things = []
end
Parent.things << :car
Child.things << :doll
mom = Parent.new
dad = Parent.new
p Parent.things #=> [:car]
p Child.things #=> [:doll]
p mom.things #=> [:car]
p dad.things #=> [:car]
Class variable:
class Parent
@@things = []
def self.things
@@things
end
def things
@@things
end
end
class Child < Parent
end
Parent.things << :car
Child.things << :doll
p Parent.things #=> [:car,:doll]
p Child.things #=> [:car,:doll]
mom = Parent.new
dad = Parent.new
son1 = Child.new
son2 = Child.new
daughter = Child.new
[ mom, dad, son1, son2, daughter ].each{ |person| p person.things }
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
With an instance variable on a class (not on an instance of that class) you can store something common to that class without having sub-classes automatically also get them (and vice-versa). With class variables, you have the convenience of not having to write self.class
from an instance object, and (when desirable) you also get automatic sharing throughout the class hierarchy.
Merging these together into a single example that also covers instance variables on instances:
class Parent
@@family_things = [] # Shared between class and subclasses
@shared_things = [] # Specific to this class
def self.family_things
@@family_things
end
def self.shared_things
@shared_things
end
attr_accessor :my_things
def initialize
@my_things = [] # Just for me
end
def family_things
self.class.family_things
end
def shared_things
self.class.shared_things
end
end
class Child < Parent
@shared_things = []
end
And then in action:
mama = Parent.new
papa = Parent.new
joey = Child.new
suzy = Child.new
Parent.family_things << :house
papa.family_things << :vacuum
mama.shared_things << :car
papa.shared_things << :blender
papa.my_things << :quadcopter
joey.my_things << :bike
suzy.my_things << :doll
joey.shared_things << :puzzle
suzy.shared_things << :blocks
p Parent.family_things #=> [:house, :vacuum]
p Child.family_things #=> [:house, :vacuum]
p papa.family_things #=> [:house, :vacuum]
p mama.family_things #=> [:house, :vacuum]
p joey.family_things #=> [:house, :vacuum]
p suzy.family_things #=> [:house, :vacuum]
p Parent.shared_things #=> [:car, :blender]
p papa.shared_things #=> [:car, :blender]
p mama.shared_things #=> [:car, :blender]
p Child.shared_things #=> [:puzzle, :blocks]
p joey.shared_things #=> [:puzzle, :blocks]
p suzy.shared_things #=> [:puzzle, :blocks]
p papa.my_things #=> [:quadcopter]
p mama.my_things #=> []
p joey.my_things #=> [:bike]
p suzy.my_things #=> [:doll]
Related Topics
Sending Http Post Request in Ruby by Net::Http
Re-Opened Nested Module Anomaly in Ruby
Dynamically Get Object's Attribute
Best Way to Use HTML5 Data Attributes with Rails Content_Tag Helper
Ruby: How to Join Elements of an Array Together with a Prefix
How to Parse a Number from a String That May Have a Leading Zero
Rails Elasticsearch Aggregation
Where Do You Put CSS Files in a Rails App Directory
Can Multiple Sidekiq Instances Process The Same Queue
Why Array.Reverse_Each Is Faster Than Array.Reverse.Each
Ruby on Rails Looks for CSS in Assets Instead of Public/Stylesheets
User Selected CSS Stylesheet in Rails
Can You Create/Write/Append a String to a File in a Single Line in Ruby
Linux Cli: How to Render Arabic Text into Bitmap
What's The Most Efficient Way Get The First Day of The Current Month
Converting External CSS to Inline CSS for Mail in Rails
Generate a 'Link_To' to the Controller Action 'Edit', Dynamically