1

I understand that instance variables inside classes can be denoted by prefixing the variable name with the @ symbol. There are a few practical applications of this in classes What does @@variable mean in Ruby?

What is a practical application of doing this inside a function?

def foo
    one = 1
    @two = 2
end
Community
  • 1
  • 1
user784637
  • 15,392
  • 32
  • 93
  • 156

3 Answers3

4

That's an instance variable. It's value persists on an instance.

class Foo
  def set_baz
    @baz = 1
  end

  def get_baz
    @baz
  end
end

foo = Foo.new
foo.get_baz #=> nil
foo.set_baz
foo.get_baz #=> 1


foo2 = Foo.new
foo.get_baz #=> nil

As you can see we can set @baz from within any method and it's updated on the instance, where we can fetch it later.


The @ prefix sets and gets instance variable on self, whatever self is. Say I boot up irb, now self is an object context created to run code in. As you create your own classes with your own code, the value of self (aka, the context) will change in various methods throughout your app.

2.0.0-p0 :001 > @foo = 123
 => 123 
2.0.0-p0 :002 > self.instance_variable_get :@foo
 => 123 
2.0.0-p0 :003 > self
 => main
2.0.0-p0 :004 > self.class
 => Object

But really, I wouldn't set instance variables unless you are in a class. You'll just confused yourself and there isn't really a good reason to do it.

I'd say, as a rule of thumb, if you don't know exactly what self is at a line of code, you shouldn't be setting instance variables on it at all.

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
  • Yes - but what does this mean in a regular function, not a method of a class? – user784637 Aug 13 '13 at 22:27
  • 1
    It's an instance variable on whatever `self` currently is. Which is likely the global singleton instance of `Kernel` (I think...) Everything is an instance of something in ruby, and you are doing class based programming wether you realize it or not. – Alex Wayne Aug 13 '13 at 22:29
  • There's no such thing as a "regular function" in Ruby. *Everything* is a method on some object somewhere. As a practical matter, though, if you just use the default object, then anything stored in an `@` variable persists between invocations, and is also visible to other functions called from the same context. Variables without the `@` go away when the function returns. – Mark Reed Aug 13 '13 at 22:32
  • @user784637 See my edit, which explains how instance variables behave without any explicit classes. – Alex Wayne Aug 13 '13 at 22:34
  • 1
    Spelling cop here, *wether* != *whether*, look up [wether](http://en.wikipedia.org/wiki/Wether) and you'll see why you probably want to use *whether you realize it or not* in your comment. – mu is too short Aug 13 '13 at 22:51
0

Your question indicates that you might be confusing @ with @@. The former is tied to a specific instance of a class; the latter is shared by all objects of the class. To expand on Alex's answer:

class Foo
  def set_baz(n)
    @baz = n
  end

  def set_zoo(n)
    @@zoo = n
  end

  def get_baz
    @baz
  end

  def get_zoo
    @@zoo
  end
end

foo = Foo.new
bar = Foo.new

foo.set_baz(1) 
foo.get_baz   # 1

bar.set_baz(2)
bar.get_baz   # 2

foo.get_baz   # still 1

foo.set_zoo(3) 
foo.get_zoo   # 3

bar.set_zoo(4) 
bar.get_zoo   # 4

foo.get_zoo   # also 4
Mark Reed
  • 91,912
  • 16
  • 138
  • 175
  • A class variable outside of your own class would likely be _way_ more confusing to get your head around than an instance variable. ;) – Alex Wayne Aug 13 '13 at 22:36
0

What is a practical application of doing this inside a function method?

class Dog
  def foo
    one = 1
    @two = 2
  end

  def bar
    puts @two
    puts one
  end

end

d = Dog.new
d.foo
d.bar

--output:--
2

1.rb:9:in `bar': undefined local variable or method `one' for #<Dog:0x00000101086810 @two=2> (NameError)
    from 1.rb:16:in `<main>'

Local variables, the ones without an @ in front of them, are destroyed when a method finishes executing.

Yes - but what does this mean in a regular function, not a method of a class?

Instance variables, the ones with a single @ in front of them, attach themselves to whatever object is self at the time they are created:

def do_stuff
  puts self   #=>main
  @val = 10
end

do_stuff   

puts self  #=>main

That output is a little unusual because self is equal to an object called main both inside the def and outside the def. Usually a def will change self--but a def doesn't change self when the def is at the the top level.

Okay, so if @val attached to an object called main, and self=main, lets print out @val:

def do_stuff
  puts self   #=>main
  @val = 10
end

do_stuff 

puts self.val  #`<main>': undefined method `val' for main:Object (NoMethodError)

Ahh, yes. All instance variables are private by default, so let's write some accessors in main's class:

def do_stuff
  puts self   #=>main
  @val = 10
end

do_stuff

puts self.class   #=>Object

class Object
  attr_reader :val
end

puts self.val   #=>10

Next, a def attaches to whatever the current class is when the def is created. The current class is either equal to self, or if self isn't a class, then the current class is self's class. In the example above, when do_stuff was created self=main:

puts self    #main

def do_stuff
  puts self
  @val = 10
end

Because self is not a class, the current class is self's class, which we can see is Object:

puts self.class   #Object

So do_stuff attaches itself to the Object class, which means it becomes an instance method of the Object class. And for extra points--it actually becomes a private instance method:

puts Object.private_methods.grep(/^do/)   #=>do_stuff

defs inside classes also attach themselves to to the current class:

class Dog
  puts self   #=>Dog

  def bark
    puts "Woof"
  end
end

...but unlike at the toplevel, the defs become public instance methods of the class.

7stud
  • 46,922
  • 14
  • 101
  • 127