Why is `instance_variable_set` necessary in Ruby? - ruby

What's the point of instance_variable_set? Aren't these two lines the same?
instance_variable_set(#name, value)
#name = value"

In the case of a "simple" variable assignment for an instance variable like:
#foo = "foo"
You couldn't do
"##{foo}" = "bar" # syntax error, unexpected '=', expecting end-of-input
But you could do something similar with instance_variable_set:
instance_variable_set("##{foo}", "bar")
p #foo # "bar"
As per your question Aren't these two lines the same?, for that example they're similar, but isn't the use people tend to give to instance_variable_set.

I wonder why there is no mention of another obvious difference: they have different scopes.
While #name = value is accessible only from within the scope where the instance variable is defined (read: from inside the instance,) instance_variable_set is available from everywhere to set instance variables from outside:
class C
attr_reader :name
def initialize(name)
#name = name
end
end
C.new("foo").tap do |c|
c.instance_variable_set(:#name, 42)
c.name
end
#⇒ 42

I'm pretty new to Ruby and have this question when I'm reading some tutorial. I'm curious what's the point of instance_variable_set?
The point of Object#instance_variable_set is to dynamically reflectively set an instance variable whose name may not be known at design time, only at run time.
Aren't these two lines the same?
instance_variable_set(#name, value)
#name = value
No, these lines are completely different, and they perfectly illustrate what I wrote above:
The first line sets the instance variable whose name is stored inside #name to value.
The second line sets the instance variable #name to value.

From the fine manual:
instance_variable_set(symbol, obj) → obj
instance_variable_set(string, obj) → obj
Sets the instance variable named by symbol to the given object, thereby frustrating the efforts of the class's author to attempt to provide proper encapsulation. The variable does not have to exist prior to this call. If the instance variable name is passed as a string, that string is converted to a symbol.
So the first argument isn't #name, it is :#name (i.e. a Symbol) or '#name' (a String).
The result is that instance_variable_set, as noted in the documentation, can be used to set an instance variable when you know its name even if you don't know the name until your code is running.

Here is an example of how the methods Object#instance_variable_set and Object#instance_variable_get could be used to increment the values of all instance variables by one.
class Klass
attr_accessor :a, :b, :cat
def initialize
#a, #b, #c, #d = 1, 2, 3, 4
end
end
k = Klass.new
#=> #<Klass:0x0000000001d70978 #a=1, #b=2, #c=3, #cat=4>
k.instance_variables.each { |v| k.instance_variable_set(v, k.instance_variable_get(v)+1) }
#=> [:#a, :#b, :#c, :#cat]
k #=> #<Klass:0x0000000001d70978 #a=2, #b=3, #c=4, #cat=5>
See also Object#instance_variables.
Compared to having four separate assignment statements, fewer lines of code are needed, but there are two other, more important advantages:
there is less chance of introducing a bug (k.cut += 1); and
adding, removing or renaming instance variables does not require the value-incrementing code to be changed.
A variant of this is to substitute a dynamically-constructed array of instance variable names (e.g., [:#a, :#b]) for instance_variables above.
These may seem like unusual examples, but they are representative of a large class of operations involving instance variables in which this kind of batch processing can be used to advantage.

Related

const_defined? vs. defined? in Ruby

To test, whether a constant (say: a class) is known at a certain point in the code, I can write for instance:
if defined? :String
or I can write
if self.class.const_defined? :String
Is there a situation where I these two ways of testing would make a difference? Note that I don't ask about the case where I have an explicit receiver, such as MyModule.const_defined? :Something, but only for the case where I want to test whether a certain constant (which in my case happens to be a constant denoting a class) is already defined.
First things first, defined? is a keyword which behaves a bit similar similar to a method. It receives the name of the thing (variable, constant, ...) to check. What makes this method different from all others is that the parser will not resolve the value of the given name but rather check directly for whether it is defined (hence the keyword property). To check if a constant is defined, you thus have to pass the actual name (rather than a Symbol):
if defined?(String)
The const_defined? on the oither hand is more regular. It expects a Symbol or String with the name of a constant and checks whether it is defined on the receiver.
Now as for the differences between the two (when used correctly): if you use them both within the context of an instance method to check for the existence of a constant, they work the same.
When running e.g. in a class definition (such that self is e.g. a class), you need to make sure to use the correct receiver for your const_defined method, e.g. if self.const_defined? :String.
Also, defined? can check for a lot more than just constants (e.g. methods, expressions, variables, ...)
If you want to use this to make sure you actually have the name of a constant at hand in a given variable, you need to use const_defined?. If you want to "statically" check whether an constant was defined, you can use defined?.
defined? is a keyword that will check if an expression exists in the current scope.
const_defined? is a method that will check if a constant exists through the ancestor chain of the receiver.
planet = "Earth"
class Experiment
def diff
""
end
def show
puts "defined" if defined?(diff)
puts "Earth not found" if !defined?(planet)
puts "String constant defined" if self.class.const_defined?(:String)
end
end
Experiment.new.show
#=> defined
#=> Earth not found
#=> String constant defined
p Experiment.ancestors #=> [Experiment, Object, Kernel, BasicObject]
p String.superclass #=> Object
Here's an example of situations where this will make a difference:
Using defined?(Nothing's printed)
class Lab
class Coco
end
end
class Experiment
def diff
""
end
def show
puts "defined" if defined?(Coco) #=> Nothing printed
end
end
Experiment.new.show
Using self.class.const_defined? (Something's printed)
class Lab
class Coco
end
end
class Experiment < Lab
def diff
""
end
def show
puts "defined" if self.class.const_defined? :Coco #=> defined
end
end
Experiment.new.show
p Experiment.ancestors #=> [Experiment, Lab, Object, Kernel, BasicObject] We find 'Lab' class in the ancestor chain.
To test, whether a constant (say: a class) is known at a certain point in the code, I can write for instance:
if defined? :String
or I can write
if self.class.const_defined? :String
Is there a situation where I these two ways of testing would make a difference?
These two really do two completely different things. The first tests whether the Symbol literal :String is defined. Obviously, a literal will always be defined, so this expression will always be true.
The second will check whether the constant String is defined, but not starting at the current constant lookup scope, instead starting at the class of self.
TL;DR
There may be cases where you can use them interchangeably, but one is a keyword and the other a method. In addition, the semantics and return values of the two are quite different.
Keywords vs. Methods
Among other things, one key difference is that Module#const_defined? is a method on a class or module that looks up constants in a class and its ancestors, while defined? is a keyword that determines whether its argument is currently known at the calling point in your code.
For example:
char = 'a'
char.const_defined?
#=> NoMethodError (undefined method `const_defined?' for "a":String)
defined? char
#=> "local-variable"
Exceptions vs. Return Values
If you're only concerned about constants, then the main difference is that you can use defined? to determine whether a constant is currently in scope without triggering a NoMethodError exception. For example:
defined? String
#=> "constant"
defined? FooBarBaz
#=> nil
As a bonus, defined? will tell what type of object you're passing as an argument (e.g. "constant"), while #const_defined? returns a truthy value.
Float.constants
#=> [:ROUNDS, :RADIX, :MANT_DIG, :DIG, :MIN_EXP, :MAX_EXP, :MIN_10_EXP, :MAX_10_EXP, :MIN, :MAX, :EPSILON, :INFINITY, :NAN]
defined? Float::NAN
#=> "constant"
Float.const_defined? :NAN
#=> true
As a rule of thumb, it's often considered best practice to reserve exceptions for handling something unexpected that may require your application to halt. Introspection or branching should generally rely on return values or Booleans, so defined? is usually a better choice if you aren't already expecting a given class to already be defined and available within the current scope.
Is there a situation where I these two ways of testing would make a difference?
const_defined? only checks the receiver and its ancestors, but it doesn't take the current module nesting into account:
module Foo
ABC = 123
class Bar
def self.test
p defined?(ABC) #=> "constant"
p const_defined?(:ABC) #=> false
end
end
end
In order to do so, you have to traverse Module.nesting:
module Foo
ABC = 123
class Bar
def self.test
p defined?(ABC) #=> "constant"
p Module.nesting.any? { |m| m.const_defined?(:ABC) } #=> true
end
end
end

Ruby: Retrieve local variable from class

I was reading up on metaprogramming and came across this exercise:
http://ruby-metaprogramming.rubylearning.com/html/Exercise_1.html
The question is:
Given this class definition:
class A
def initialize
#a = 11
##a = 22
a = 33
end
#a = 1
##a = 2
a = 3
end
Retrieve all the variables from outside the class, with output like so:
1
2
3
11
22
33
Now, it's pretty straightforward to get the instance and class variables dynamically, even the local variable inside the constructor (it's the return value of the initialize method). But I'm stumped as to how to get the local variables a=3.
As far as I know, this is not possible because the local variables cease to exist after the class definition is first read.
The only roundabout way that I have made this work is to set a variable to the "return" value (for lack of a better term) of when the class is declared, like so:
val = class A
a = 3
end
puts val # => 3
Is this the only way?
The question seems to boil down to this: given the following:
class A
attr_reader :instance_var
def initialize
#instance_var = (#instance_var ||= 0) + 1
instance_local_var = 33
puts "instance_local_variables = #{ local_variables }"
instance_local_var = 33
end
class_local_var = 3
puts "class_local_variables = #{ local_variables }"
class_local_var = 3
end
# class_local_variables = [:class_local_var]
#=> 3
can one determine the values of instance_local_var and class_local_var?
Determine the value of class_local_var
The answer to this question is clearly "no" because class_local_var no longer exists (has been marked for garbage collection) after end is executed1:
A.send(:local_variables)
#=> []
Determine the value of instance_local_var
a = A.new
# instance_local_variables = [:instance_local_var]
#=> #<A:0x007ff3ea8dbb80 #instance_var=1>
Note that #instance_var #=> 1.
A.new does not return the value of instance_local_var, but because that variable is assigned a value in the last line of initialize, that value can be obtained by executing initialize once again.2
instance_local_var = a.send(:initialize)
#=> 33
There is a problem, however:
a.instance_var
#=> 2
Executing initialize a second time has caused an unwanted side effect. My definition of initialize is artificial, but it highlights the fact that many undesirable side effects could occur by executing initialize a second time.
Now let's obtain a new instance.
b = A.new
# instance_local_variables = [:instance_local_var]
#=> #<A:0x007fee0996e7c8 #instance_var=1>
Again, #instance_var=1. One possible workaround to the side-effects of calling initialize twice for a given instance is to subclass A and use super.
class B < A
attr_reader :b
def initialize
#b = super
end
end
B.new.b
#=> 33
a.instance_var
#=> 1
There is no guarantee that undesirable side-effects can be avoided with this approach (e.g., initialize for any instance may perform a database operation that should occur only once), but it appears to leave the initial instance a unaffected. This is of course all hypothetical.
1. send must be used because A.private_methods.include?(:local_variables) #=> true
2. A.new.send(:initialize) is required because iniitialize is private.
Your question is unclear. In the title, you write "local variables", but in the example, you mention only instance- and class-variables.
As for the instance variables, you can use Object#instance_variables to get a list of known instance variables at this point. Note however that instance variables are created dynamically, not at the time of class declaration. For example, given the class
class AA;
def initialize; #x=1; end;
def f; #y=1; end;
end
the expression
AA.new.instance_variables
would return [:#x] - the :#y is missing, because it doesn't exist yet.
You don't have a way to automatically (i.e. without modifying the class) retrieve local variables. As mudasobwa explained in his answer, you would have to explictly pass back a binding.
One might get an access to all the local variables of the class by returning it’s binding from the class definition (see Binding#local_variables for details):
a = class A
v1 = 3.14
v2 = 42
binding
end
a.local_variable_get(:v1)
#⇒ 3.14
a.local_variable_get(:v2)
#⇒ 42
But the main question is why would you want to do that? The local variable is meant to remain local. This is how it is supposed to behave. Also, one is unable to modify the local variable in the original binding (what is returned is a read-only copy of an original binding.)

"Anti-private" property of setter method

Getter methods can be used without an explicit receiver unless there is a local variable with the same name:
class A; attr_reader :foo end
A.new.instance_eval do
#foo = :foo
p foo
end
# => :foo
This will not hold when there is a local variable with the same name, due to the principle that interpretation as a local variable has priority than as a method call whenever there is an ambiguity.
class A; attr_reader :foo end
A.new.instance_eval do
foo = :bar
#foo = :foo
p foo
end
# => :bar
However, setter methods cannot be used without an explicit receiver even when a local variable with the same name is not assigned prior to the expression in question:
class A; attr_writer :foo end
A.new.instance_eval do
foo = :foo # <= No local variable named `foo` has been assigned before this point
p #foo
end
# => nil
How is this "anti-private" property of setter method justified?
If ruby interpreted your assignment in your last statement as an assignment to self, you would have no way left to set a local variable.
The way it is leaves no ambiguity for the interpreter to deal with: assignments without self are always local variables, assignments to self are always trying to use a writer on the object.
If it were the other way around
The interpreter would have to look up the contexts writer methods and assign it via the writer if there is one, which almost certainly would have a negative impact on performance
class A
attr_writer :foo
end
A.new.instance_eval do
# for each of these assignments, the interpreter has to look up if there's
# a writer method defined
foo = 'bar'
bar = 'baz'
fib = 'buz'
end
It would also leave the programmer with the rather stupid task to find out every setter method of the context he's in before assigning local variables to make absolutely sure he does not unintentionally use a setter.
class C
attr_writer :something
end
class B < C
attr_writer :foo
end
class A < B
attr_writer :bar
end
A.new.instance_eval
something = 'something'
#you just (almost certainly with no intention) assigned a value to an attribute
end
Also, your question reads:
setter methods cannot be used without an explicit receiver even when a
local variable with the same name is not assigned prior to the
expression in question:
If it were the other way around, you could not assign a local variable with the same name prior to the expression in question, because the assignment would use the setter (as stated in the first paragraph of this answer)
Concerning the implementation / the access to variables the attribute methods use: Getter and Setters work with instance variables. So, for example attr_accessor actually defines something like this:
def foo
#foo
end
def foo=(data)
#foo = data
end
So, the attribute is declared as a instance variable and not as a local variable, why should the programmer be able to assign it like a local variable? This would leave the wrong impression that you could assign instance variables of an object via assigning local variables. If ruby would do this, it would almost certainly lead to a serious memory management problem. To make it short: foo = 'bar' and #foo = 'bar' are not the same, and exactly because the attr methods use #foo = 'bar', you can not call them via using foo = 'bar'.
I think #sawa finally clarified what is meant by "anti-private".
sawa's comment:
Private means it cannot have an explicit receiver. Negation of that would be that it may have an explicit receiver, which is not what I am mentioning. I am mentioning a case where a method must have an explicit receiver, which is against private. I think you are confused.
I was confused, apparently along with all the other commenters, because "anti-private" and "against private" aren't standard terminology, nor was the meaning immediately obvious.
I think the meaning of the original question is: "Since setters require an explicit receiver, and private forbids explicit receivers, how can I call a private setter?" In other words, "anti-private" means "incompatible with private", or "unusable with private".
Jörg W Mittag eloquently explains an exception to the normal private rules. Basically, setters can be called on self even if they are private, because there's no other way to call them (unless you use the cumbersome send).
So, a setter's requirement of an explicit receiver is perfectly compatible with the setter being private, only because of the exception to the rule.
Beat Richartz's answer is pretty complete already, but I want to highlight one point about the behavior you're proposing.
In your question you have this sample code:
class A; attr_writer :foo end
A.new.instance_eval do
foo = :foo # <= No local variable named `foo` has been assigned before this point
p #foo
end
You are proposing that the assignment call the setter method. And you want this to happen if the local-variable foo hasn't been assigned yet.
But what syntax would you use to assign the local before that point?
If the receiverless assignment foo = :foo means call the setter (when it exists), you'd need yet another syntax construct to mean "assign this local-variable, disregarding whether there is a setter".
I honestly do want to hear your proposal (I'm not being sarcastic) if you have one. It would be interesting to hear alternative views on language design.
I'm not saying your way would be necessarily "worse" than the current ruby way. But at some point a language designer has to decide default behaviors for ambiguous situations, and Matz decided that receiverless assignment assigns the local.

Ruby: Automatically set instance variable as method argument?

Are there any plans to implement ruby behavior similar to the CoffeeScript feature of specifying an instance variable name in a method argument list?
Like
class User
def initialize(#name, age)
# #name is set implicitly, but #age isn't.
# the local variable "age" will be set, just like it currently works.
end
end
I'm aware of this question: in Ruby can I automatically populate instance variables somehow in the initialize method? , but all the solutions (including my own) don't seem to fit the ruby simplicity philosophy.
And, would there be any downsides for having this behavior?
UPDATE
One of the reasons for this is the DRY (don't repeat yourself) philosophy of the ruby community. I often find myself needing to repeat the name of an argument variable because I want it to be assigned to the instance variable of the same name.
def initialize(name)
# not DRY
#name = name
end
One downside I can think of is that it may look as though a method is doing nothing if it has no body. If you're scanning quickly, this may look like a no-op. But I think given time, we can adapt.
Another downside: if you're setting other instance variables in the body, and you try to be readable by putting all the assignments at the beginning, it can take more cognitive "power" to see that there assignments also happening in the argument list. But I don't think this is any harder than, say, seeing a constant or method call and having to jump to its definition.
# notice: instance var assignments are happening in 2 places!
def initialize(#name)
#errors = []
end
After some pondering, I wondered if it's possible to actually get the argument names from a ruby method. If so, I could use a special argument prefix like "iv_" to indicate which args should be set as instance variables.
And it is possible: How to get argument names using reflection.
Yes! So I can maybe write a module to handle this for me. Then I got stuck because if I call the module's helper method, it doesn't know the values of the arguments because they're local to the caller. Ah, but ruby has Binding objects.
Here's the module (ruby 1.9 only):
module InstanceVarsFromArgsSlurper
# arg_prefix must be a valid local variable name, and I strongly suggest
# ending it with an underscore for readability of the slurped args.
def self.enable_for(mod, arg_prefix)
raise ArgumentError, "invalid prefix name" if arg_prefix =~ /[^a-z0-9_]/i
mod.send(:include, self)
mod.instance_variable_set(:#instance_vars_from_args_slurper_prefix, arg_prefix.to_s)
end
def slurp_args(binding)
defined_prefix = self.class.instance_variable_get(:#instance_vars_from_args_slurper_prefix)
method_name = caller[0][/`.*?'/][1..-2]
param_names = method(method_name).parameters.map{|p| p.last.to_s }
param_names.each do |pname|
# starts with and longer than prefix
if pname.start_with?(defined_prefix) and (pname <=> defined_prefix) == 1
ivar_name = pname[defined_prefix.size .. -1]
eval "##{ivar_name} = #{pname}", binding
end
end
nil
end
end
And here's the usage:
class User
InstanceVarsFromArgsSlurper.enable_for(self, 'iv_')
def initialize(iv_name, age)
slurp_args(binding) # this line does all the heavy lifting
p [:iv_name, iv_name]
p [:age, age]
p [:#name, #name]
p [:#age, #age]
end
end
user = User.new("Methuselah", 969)
p user
Output:
[:iv_name, "Methuselah"]
[:age, 969]
[:#name, "Methuselah"]
[:#age, nil]
#<User:0x00000101089448 #name="Methuselah">
It doesn't let you have an empty method body, but it is DRY. I'm sure it can be enhanced further by merely specifying which methods should have this behavior (implemented via alias_method), rather than calling slurp_args in each method - the specification would have to be after all the methods are defined though.
Note that the module and helper method name could probably be improved. I just used the first thing that came to mind.
Well, actually...
class User
define_method(:initialize) { |#name| }
end
User.new(:name).instance_variable_get :#name
# => :name
Works in 1.8.7, but not in 1.9.3. Now, just where did I learn about this...
I think you answered your own question, it does not fit the ruby simplicity philosophy. It would add additional complexity for how parameters are handled in methods and moves the logic for managing variables up into the method parameters. I can see the argument that it makes the code less readable a toss up, but it does strike me as not very verbose.
Some scenarios the # param would have to contend with:
def initialize( first, last, #scope, #opts = {} )
def search( #query, condition )
def ratchet( #*arg )
Should all of these scenarios be valid? Just the initialize? The #*arg seems particularly dicey in my mind. All these rules and exclusions make the Ruby language more complicated. For the benefit of auto instance variables, I do not think it would be worth it.

Ruby newbie question: hashes

i have the following
class test
hash={}
def printHash
puts hash[1]
puts hash[2]
puts hash[3]
end
end
test.new.printHash
this prints:
1
0
1
Why does this happen? how can i test whether or not i have put something in that spot of the hash? or am i missing something
You're well off the mark, but it appears to be doing something because hash is a builtin function which returns a Fixnum hashcode for the object. When you use square brackets on a Fixnum, you get the value of the specific bit. What you want to do is to create an instance variable, which starts with the sigil #. Also, you have to create instance variables within a method, so we'll use the one that's called whenever an object of the class is created, initialize:
class Test
def initialize
#hash = {}
end
def printHash
puts #hash[1]
puts #hash[2]
puts #hash[3]
end
end
Now you'll find this prints nil for all three. To test whether a hash has a value for a specific key, you can use has_key?.
Basically 'hash' is out of scope, what you are referencing in your printHash function is a different object altogether, normally it would be nil (a new unassigned object) but as Pesto points out 'hash' is a built in function - somewhat confusing this explanation.
By putting an '#' sign in front of the your variable and assigning it in the initialize method (which is called after 'new') it becomes available in the entire instance of your object.

Resources