10

What's the point of instance_variable_set? Aren't these two lines the same?

instance_variable_set(@name, value)
@name = value"
3
  • Possible duplicate of How to properly set an instance variable with instance_variable_set? Commented Oct 28, 2018 at 2:26
  • 1
    @matt, close, but the linked question is only asking why the colon is necessary. Commented Oct 28, 2018 at 4:29
  • 2
    if you used instance_variable_set("@name", value) they would be the same. (note the quotation marks around @name) Commented Oct 28, 2018 at 6:44

5 Answers 5

17

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.

Sign up to request clarification or add additional context in comments.

1 Comment

As stated here, as well as the obvious benefit/consequence of ignoring whether there is a public attr_writer or attr_accessor. A publicly unexposed instance variable can be set using this.
8

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

1 Comment

I interpreted the OP as asking why one would not just rely on setters for changing the values of instance variables outside the class, but I now see the code in the question may suggest otherwise.
5

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.

Comments

1

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.

1 Comment

μ, thanks for bringing that doc to my attention. It prompted me to post a suggestion at Ruby trunk. :-)
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.