Variable Scope: Global, Constant, Class, Instance, Local

Saturday, December 6, 2014

We are wrapping up Week 6 of Phase 0 where we've played around with scope. Scope defines where in a program a variable is accessible. There are five types of variable scope: global, constant, class, instance, and local. See below for more info:

$Global Variables

Global variables are prefixed with $. They are visible throughout the program, meaning it can be outside of methods and classes. Typically global variables are to be avoided. Because it is accessible throughout the program, if a class or method modifies the global variable, whatever other class or method that also uses that global variable will behave in an unexpected and undesirable way. It would then make debugging difficult because it'd may be challenging to figure out what modified the global variable and when. Typically we use already established global variables with single character names, for example $0 technically does something (not related to having zero money).

CONSTANT Variables

Constant variables are defined by being in all caps (CONSTANT) or having the first letter capitalized (Constant). Constant variables have values that are to remain constant and unchanged. However, it is possible to change the value but you will get a warning. It is like having an auntie who is supposedly 40 years old every year, she somehow mysteriously never ages.

Using irb in our console:


    puts "me: How old are you, Auntie?"
    puts "*silence*"
    AGE = 40
    puts "Auntie: I am #{AGE} years old."
    puts "Dad: Really?? Weren't you #{AGE} five years ago?"
    => me: How old are you, Auntie?
    => *silence*
    => Auntie: I am 40 years old.
    => Dad: Really?? Weren't you 40, like five years ago?

    AGE = AGE + 5
    => warning: already initialized constant AGE
    => warning: previous definition of AGE was here

    puts "me: That means you're actually... #{AGE}!!"
    puts "*Auntie storms out* "
    => me: That means you're actually... 45!!
    => *Auntie storms out*
  

As you see, when you change the constant AGE by adding 5 (years), you get a warning sign saying you had previously given it a value of 40 and you shouldn't be changing it, but it went ahead and changed it to 45. It's kind of similar to getting a warning sign "be careful, you're about to add 5 years to the age she just told you and reveal her real age, she's going to be pissed." So yeah, it's a good idea to let constants be constants.

@@Class Variables

Class variables are noted with @@ in front of the variable name. They can be used inside and outside of methods, which means it can also be inside classes. It is also required to initialize it. Why? If the class variable's value is modified in one stance, the new value will be used for the other instances as well. There can only be one variable value for all objects instantiated from the class. This means that if the value changes for the class variable, it will do so in all the object instances (methods) it appears in.

Going into our console and running our ruby file:


  class Party

    def initialize
       @@party_year = 1999
      puts "Let's party like it's #{@@party_year}!"
    end

    def best_year
      @@party_year
      puts "The best year is #{@@party_year}!"
    end

    def change_year=(num)
      @@party_year = num
      puts "No... the best year is actually #{@@party_year}."
    end
  end


  genX = Party.new
  genX.best_year
  genX.change_year = 2000
  genX.best_year
  => Let's party like it's 1999!
  => The best year is 1999!
  => No... the best year is actually 2000.
  => The best year is 2000!


  

So thinking about Prince's song "Party like it's 1999", we can set our @@party_year = 1999 in the initialize method, since apparently that was THE year to party. If we define a method called best_year, it will tell us @@party_year 1999 is the best year. However with the method change_year where we are setting it to 2000, @@party_year is now updated to 2000. When we run best_year method again, it no longer says 1999, it is now 2000, even though we had originally agreed with Prince that 1999 was the best year!

@Instance Variables

Instance variables start out with just one @. Instance variables and class variables may seem to do the same thing, but actually class variables can be used for different classes and exist over all instances of class. You can only use the instance variable inside different instance methods and get different values. Let's use the same example as earlier but reformat it as instance variables.


  class Party

    def initialize(year, birth_year)
      @party_year = year
      @birth_year = birth_year
      puts "Let's party like it's #{@party_year}!"
    end

    def drinking_year
      best_year = @birth_year + 21
      puts "The best year was #{best_year} when I turned 21!"
    end
  end


  genX = Party.new(2000, 1986)
  genX.drinking_year
  => Let's party like it's 2000!
  => The best year was 2007 when I turned 21!

From here you see that we have initialized instance variables @party_year and @birth_year, which were given to us as parameters so that we can use them for different methods. We will need to use @birth_year later for drinking_year method where we add 21 years to it to find your drinking_year. As you see, best_year doesn't have anything attached to its name. This means it is a local variable. See below for an explanation on local variables.

Local Variables

Local variables are in lowercase, don't have any special notations before it, but can have an underscore in between. The accessibility of local variables is only inside the method, they can't be used for anything else outside of that parent method. So here we see that best_year is a local variable for drinking_year because that's the only time we need that variable.

I think I understand variable scope now, finally