LeongZeno LeongZeno - 2 months ago 8x
Ruby Question

Difference between @foo, self.foo, and foo?

class Artist
@@song_count = []
attr_accessor :name, :songs

def initialize(name)
@name = name
@songs = []

def add_song(song)
@songs << song

def print_songs
songs.each {|song| puts song.name}

So in this example, it uses all two types, @songs and songs.

I'm having a hard time understanding why these are used, instead of using @songs for everything.

And then in this example,

def add_song(song)
self.songs << song
song.artist = self
@@song_count +=1

Why is self.songs used instead of @songs?

Ok, so I forgot to say one more thing. In the first code snippet above,for method print_songs, why am I able to use songs.each instead of @songs.each? I was expected it to generate an error undefined songs.


Why is self.songs used instead of @songs

Using the method is more flexible. You're abstracting yourself from knowing how exactly it gets/stores data. The less you rely on implementation details, the easier it will be for you to change code later.

One small example, consider this implementation of songs

def songs
  @songs ||= []

@songs may or may not have been assigned value prior to invocation of this method. But it doesn't care. It makes sure that @songs does have a sane default value. The concept is called "lazy initialization" and it's very tedious and error-prone to do if you use instance variables directly.

So, when in doubt, always use methods.