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.
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] >> 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 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
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 endend#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
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. |
