[Basics] 1 Ruby Variables

Ruby Variables...

    Disclaimer

    Ruby as do just about all other programming languages, uses the concepts of variables to store data. A quick Google search on the term variable in the context of programming (search:variable + programming), will return loads of great info on variables, their implementations and more. Here we will certainly delve into this topic, however it will be Ruby based. If you have no idea what a variable is, you may sit along for the ride however it may get bumpy at certain stops. 

What are variables?

    Variables are containers for information. They can hold different "types" of data. A variable is named as such, because the data contained is subject to change. There is a hard distinction between this and something that is expected to remain static (constants). A variable should not be used to contain static data or data which is not intended to change ever. 

    In Ruby, variables match the above description. In order to declare a variable in Ruby, one must use an assignment operator. The assignment operator is the '=' sign. What this ends up looking like functionally is below. 

#Declaring a variable named "variable" to be equal to the string "text".
>> variable = "text"
=> "text"

#Declaring a variable named "variable" to be equal to the numeric value 1.
>> variable = 1
=> 1

NOTICE: We are simply defining here how to declare variables, we are not discussing the different types of variables and how they are defined. 


Dynamically Typed

    Ruby is dynamically typed unlike other programming languages (like C and Java) and a variables data is tagged at run time to be of a certain type. What this means to the Ruby programmer is that he does not need to declare a variable as a specific type.

    Looking for a comparison point, The C language comes to mind (which is a low level compiled language where Ruby is a high level  interpreted language). In the C language when a variable is declared the type of data it will contain must be specified. Once that variable is declared putting a separate type of data into it would then raise an error from the compiler. For an example of how variable declaration in a language like C looks, take a gander below: 

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char text[5] = "text";
    printf("%s\n", text);
}


    I save this code snippet to a text file named "variable.c" and I compile this code (because C is a compiled language where Ruby is interpreted). After compiling the code a binary file is produced which I can now run.


rainofkayos@animal ~ [3998] % gcc -o variable -ansi variable.c
rainofkayos@animal ~ [3999] % ./variable                    
text

    This program simply defines a character (string) type variable which can be 5 characters at most. It simply prints this character defined in the code and a new line to the screen. 

    OK so lets disobey our type setting so we can get to the point. Lets put 10 characters into our variable and LEAVE our variable definition at 5 characters and try to recompile and run this code.


#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char text[5] = "texttextte";
    printf("%s\n", text);
}

rainofkayos@animal ~ [4002] % gcc -o variable -ansi variable.c
/tmp/variable.c: In function 'main':
/tmp/variable.c:6:20: warning: initializer-string for array of chars is too long

    We were not able to compile this because the compiler detected the error in our variable. There would be two ways to fix this, increase the amount of characters in the variable declaration, or decrease the amount of characters in the actual variable data. 

    Ruby does NOT have this problem (or concept). Ruby is dynamically or weakly typed, as a pose to C's adverse strong typing. As such, variables in Ruby are not declared with a type, they are simply declared and Ruby does the type assignment behind the scenes. 

    Ruby doesn't really care much about you changing a variable from type to type. Lets take a look at some Ruby variable declarations.

    First I would like to mention that many times in this blog you will see me refer to an application called IRB. IRB stands for interactive ruby. As Ruby is an interpreted language and not compiled, there is no need for that step of compiling code to a binary object. Code is executed as it is interpreted. This is why Ruby is an interpreted language (As well as Perl, PHP, and Python). The IRB is a shell similar to a bash shell where I can type commands. These "commands" are actually Ruby code which is executed as I type. So lets declare some variables in irb.

#Declaring a variable of string class
>> name = "aaron"
=> "aaron"

#Declaring a variable of fixed number class.
>> number = 1
=> 1

#Declaring a variable that hold an object[1]
>> object = Object.new
=> #<Object:0x7f60d49f3e40>

[1] Actually these are all objects, as just about everything in Ruby is an object.

    So here we declared 3 variables, name, number, and object. Each holding the data that the variable name implies. Notice that we did not state what the variable data type is as we did in C. We also did not need to give any parameters like how many characters will be in our strings. Well a good question now is, how do you know what type of data is in a variable?

    One way to know is to be aware of some common gotchas. 
  • Strings are enclosed in single or double quotes. (Double quotes allow for interpolation of variables and expressions into a string)
  • A variable you expect to be a number should NOT be in quotes else it will be handled like a string.
  • Ruby is polymorphic (we will explain that later). This means that you can call methods with the same name on many different types of objects. For example "+" is a method in Ruby. Depending on the class of data, is what the result of using the + method will be. If you + two numbers, you will get what you expect, the sum. However + two strings, and you will get a concatenation of the two strings. Try it out on 2 arrays....Why this is relevant is because you should be aware of the data in your variables or the results of your operations may be unexpected.
    Another way to know is to use Ruby's reflection (the ability to inspect itself and also ability to change itself based on it looking at itself, more on this later) capabilities and query a variable for information.

    Exposed via class inheritance and module mixing in, are many methods which provide core functionality like the ability to print, get data from the keyboard, and determine a variable or objects type (class). Here we call a method named "class" on these variables we just declared, we will observe what is returned by this method call.

#Calling the class method on name, reveals it is of String Class.
>> name.class
=> String

#Calling class method on number, reveals it is of FixNum Class.
>> number.class
=> Fixnum

#Calling class method on object, reveals it is of Object Class.
>> object.class
=> Object

    In short, variables hold data, this data in Ruby will most likely by an Object. We have now covered how to declare a variable in ruby (a local variable).

More funky ways of declaring variables.

    The right hand side of an assignment operator does not necessarily need to be a hard value. It can very well be Ruby code.

#Defining a as the result of calling the map method on a statically defined array.
a = [1,2,3,4].map! {|member| member*2}
=> [2, 4, 6, 8]

#Calling the class method on the a variable, reveals it is of Array Class.
>> a.class
=> Array

We can also assign variables to other variables.

#Setting the variable a to the numeric value 10.
>> a = 10
=> 10

#Setting the variable b to the value of the variable a. (10)
>> b = a
=> 10

#Using the comparison operator to test if a and b are equal returns true.
>> a == b
=> true

We can also use expressions and variables on the right hand side of the declaration.

#Declaring the variable c to the numeric value 10, IF a + b equal 20.
>> c = 10 if a + b == 20 
=> 10

    Declaration of variables is very flexible with Ruby, no specific keyword is needed. 

Type Casting

How does Ruby handle changing variable types? 
    
    Lets quickly for comparison value look at how C handles it. Lets change our previous string value to a numeral, however lets not change the variable definition.

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char text[5] = 1 ;
    printf("%s\n", text);
}

rainofkayos@animal ~ [4009] % gcc -o variable -ansi variable.c
/tmp/variable.c: In function 'main':
/tmp/variable.c:6:5: error: invalid initializer

    So C does not like it at all, well C really doesn't like to be lied to, by declaring a variable as one type and initializing it with some other type, is a lie. Technically Ruby doesn't like lies either, however Ruby is much more forgiving with what we can do to get around this. 

#Declaring a as the number 1
>> number = 1
=> 1

#Checking the class of a, it is FixNum
>> number.class
=> Fixnum

#Using puts to print out 1 to the screen
>> puts number
1

#Using puts with variable interpolation to print the variable to screen.
>> puts "#{number}"
1

#Redefining the number variable.
>> number = "1"
=> "1"

#The class is now a string, the string is 1 

>> number.class
=> String

#Performing a math operation on the number variable, which now contains a string.
>> number + number
=> "11"

    You may be scratching your head now, or also may have laughed at the fact that Ruby can't do math. However, jokes on you, as stated, Ruby is aware of what class what objects belongs in, when you enclose the number 1 in surrounding quotes ("1"), it is no longer considered a number, it is interpreted as a string. So what Ruby has done is concatenated the 2 strings in number and number (Two 1's). The string 1 + the string 1 indeed is 11. Similar to how f + a + i + l equals fail.

#No seriously it does. That polymorphic enough for you!
>> "f" + "a" + "i" + "l"
=> "fail"

    OK so whats all the buzz about the difference in C and Ruby you asked? Well lets see. 

    First I showed you that me setting a variable to something like a number and then setting it to something like a string does NOT raise any errors. I can redefine a variable with different data to my hearts content. 

    I also showed that a variable can be shown in a string form using variable interpolation or printed in it's native format. What I haven't shown is the ability to convert an object of one class to an object of a different class. Let's look at it now. 

#Remember this? This is String Concatenation. 
>> number + number
=> "11"

#Below is similar to above HOWEVER I am using a method called to_i, which changes that string to an integer. Now suddenly 1 + 1 = 2.
>> number.to_i + number.to_i
=> 2

    For some examples of the basic types of variables Ruby uses you can reference the below list:

Ruby Data Types
  • Numbers - There are whole numbers and numbers with decimal places. Whole numbers are represented by the Fixed & Big number classes. Numbers with Decimal places are represented by the Float class, they are calculated using the native double-precision floating point. Number types are suitable to have mathematical calculations performed on them. One should be wary however of what type of operation you are performing on what type of number.
  • Strings -  A string type holds any amount or sequence of bytes. Strings can be defined literally or created via object instance:

>> string = String::new
=> ""
>> string = "literal"
=> "literal"
>> "string".class
=> String
  • Arrays - An Array is a collection of items. These items themselves can be Ruby Objects of different types. Arrays are integer indexed with the base starting at 0. The first item in an array collection has an index of 0.
  • Hashes -  A Hash is a collection of key and value pairs. Similar very much to an Array however rather than being integer indexed based it is key based. Each key has a value. 
  • Symbols - A symbol in Ruby is a representation of a name or string. They are notated by a preceding colon or by calling the to_s method on an object. Symbols can be used to avoid creating new objects. For instance if the value Fred is used multiple times in a program however Fred is not really anything but a name. Rather than use a String type over an over, which would waste memory and over head on Object creation, one can utilize a symbol which represents the same object in each calling of a programs scope.
  • Ranges - A range is a collection of values that is referenced by it's start and end value. A range can work on numerals or alphabetic characters.
Scope

    Speaking of different types of variables, we only discussed the type of data the Object in a variable may contain. However we will now speak about a common programming concept called Scope.

    What is scope? Simply explained Scope is the relevance of a defined construct in a particular section or block of code. 

    Most languages have the idea of scope, even Bash and shell scripting languages. For instance we generally see that a program has a main function (like the C program we wrote earlier). 

    The main method is "The starting point" if you will. It will generally have many methods WITHIN main which implement the actual functionality of the program as a whole. Some variables defined in main may not be visible to a function inside of main unless specifically made to be by following the concepts defined below. Take the below examples into consideration. Lets drop ourselves in main. 

#When I load up IRB, and type self, the object main is returned.This is because I am presently at the top most level of execution.

>> self
=> main

Self is as it's name implies. Self is the current object where it is called. Above you will see that I am in main. However lets say I define a Class under main and perform the self operation from there. What will it return?

#I will define a class named AaronSamuel. This simple class will have a  Class method defined named what_am_i? This method simply prints to the standard output the return from the self call interpolated into a string.

>> class AaronSamuel
>>   def self.what_am_i?
>>     puts "#{self}"
>>     end
>>   end

#Now lets call our new Class Method.
>> AaronSamuel.what_am_i?
AaronSamuel

#OK given the concept of self, let me show you something cool, at the same time something which shows the difference in the two scopes.

>> def self.what_am_i 
>>   puts "#{self}"
>>   end

#Now lets call on our Class method which is actually defined in the scope of main.

>> what_am_i
main

    So you can see here that there are separate sections of code which hold scope. Lets look at Ruby, variables and the notion of scope all together.

Variables Scope, and Ruby (tying it together)

#We define a variable and give it a string value.
>> local_variable = "aaron"
=> "aaron"

#In the main scope we can interact with this variable, below I am printing it out. 

>> puts local_variable
aaron

#Lets define a function to do the same. This function is defined under main. 

>> def print_something_silly
>>   puts local_variable
>>   end
=> nil

#So lets run the function. 
>> print_something_silly
NameError: undefined local variable or method `local_variable' for main:Object
from (irb):3:in `print_something_silly'
from (irb):5

It throws an error! 

    This is because this variable I have so appropriately named local_variable is exactly that in scope. Local. How do we know it is local? We can always determine the type (scope wise) of variable in ruby by looking at what the variable name begins with. A local variable begins with any alphabetic character or an underscore.


    As are there variables which are local in scope to the current code block, there are variables which can be called from anywhere in the program. These are called global variables. Global variables begin with a $.

#We define a global variable, and it is of String type. 
>> $global_variable = "aaron"
=> "aaron"

#Lets now fix our function. Ruby is fully dynamic, we can REDEFINE our function, editing it in place. Below we will fix it to use the global variable previously defined.

>> def print_something_silly
>>   puts $global_variable
>>   end
=> nil
>> print_something_silly
aaron
=> nil

It works!

    So here you see your first taste of scope in ruby with global and local variables. Local variables are available within their present block only. Global variables, as named are available globally through out all code blocks within main. 

    We also have Class and Instance variables. Class variables begin with @@, they are available on a class level and all objects within that class. In comparison, an Instance Variable which begins with @, is only available to an object instance of a particular class. 

    To further explain the Class and Instance variables. Lets look at classes, and instances of a class. And lets use both variable types functionally.

#Pokemon class.
        
class Pokemon   
    def initialize(name="asamuel")
        if defined?(@@count) 
            @@count += 1
        else
            @@count = 1
        end
        @name = name
    end

    def self.count
        @@count
    end
end

#Now I can create a simple Pokemon like this. (Notice that I set the default name to "asamuel" so if I don't give an argument, that is the Pokemon's name.

>> Pokemon.new
=> #<Pokemon:0x00000000b5ae50 @name="asamuel">
#Lets create some Pokemon objects and save them in variables.

>> a = Pokemon.new("pekachu")
=> #<Pokemon:0x00000000b3dfa8 @name="pekachu">
>> b = Pokemon.new("balbazar")
=> #<Pokemon:0x00000000b36668 @name="balbazar">
>> b = Pokemon.new("squirtle")
=> #<Pokemon:0x00000000b214c0 @name="squirtle">
>> a = Pokemon.new("pekachu")
=> #<Pokemon:0x00000000b09dc0 @name="pekachu">
>> b = Pokemon.new("squirtle")
=> #<Pokemon:0x0000000094a1d8 @name="squirtle">
>> c = Pokemon.new("squirtle")
=> #<Pokemon:0x0000000093a620 @name="squirtle">

#Now lets call on our count method of the Pokemon class. 
>> Pokemon.count
=> 7

    So what do we see from this? Notice that when I am creating a new Pokemon the passed in local variable name is copied to the instance variable @name. This is why you see the below in my IRB session after I create a Pokemon object.

>> a = Pokemon.new("pekachu")
=> #<Pokemon:0x00000000b3dfa8 @name="pekachu">

    Instance variables are good for saving data concerning that object. Now I also call a function defined on the class level called count. As you can see when we call initialize we have some statement to check if a class variable named @@count is defined, if not than we set it to 1, if it is defined we increment it by 1. As such, each time a Pokemon object is created, we are keeping count. Class variables are good for data which is global to all objects of a particular class.


So lets look at all the variable scope types and their sigils (I love this word)

Ruby Variables

 Variable Type Sigil Example
 Local  local_variable 
 Global $ $global_variable
 Class @@ @@class_variable
 Instance @ @instance_variable

    In ruby variables, any character from a-z is allowed, In a local variable definition, the first letter can not be Capitalized. Any numeral can be used, however in a local variable, a number can not be first, (sigils prevent a number from being first in any other variable type). Other than this underscores can also be used in variable names. Other characters are illegal.

    Language like Perl use sigils to depict the data type a variable will hold, Ruby's sigils are used to depict what scope the variable has in the program. Next posting will be about Constants.

Comments