Now that you have some basic understanding of classes, it’s time to dive a little deeper into understanding object orientation.
In the last lesson, we observed the following code:
Look at lines 13, 14 and 15, above, where we assign a value to the first_name property of each object. This is the first time we actually do something with “objects of type Person”. In lines 17,18 and 19, we are sending the value stored in the first_name property to the terminal. In all six lines of code, it’s we who are doing something with them (the objects). The objects themselves aren’t doing anything…. yet.
When we write object-oriented code, we use objects created from classes to model the world around us.. or at least.. model the things we need to model for the purpose of our application. Think of yourself as a real world object. In computer terms, you have two categories of capabilities: state and behavior. To be clear, when we say behavior in this sense, we mean the ability to do things.
OK.. let’s address state first. Surely you’ve heard the term “state of mind”, yes? Sometimes your state of mind is happiness.. other times it is sadness. Worry, anxiety, anger.. you get the picture. We also have other “kinds” of state: our body temperature, blood pressure, cholesterol.. any number of things. Very often, the only way to get at that state is to make some sort of inquiry, or test.
Behavior, on the other hand, is the name we give to our ability to perform actions… at least in computer programming parlance. For example, we walk, talk, breathe, eat, read, etc. Notice that some of our behaviors don’t require any additional input, such as walking, or talking, however, others require some sort of additional matter or input. For example, we cannot eat without food, nor can we read without words in front of us. In computer programming terms, these additional things which are required for us to perform some action are called parameters or arguments (there is a subtle difference between the two terms, but for our beginner’s purposes, we’ll think of them as completely synonymous now and differentiate them once you have these concepts more solidly formed in your mind).
Forgetting about Ruby specifically… objects (models of real world things), deal with state and behavior by storing values in properties (for state), and encapsulating behavior inside of methods.
For example.. it makes sense that a human resources application needs to model people. However, it doesn’t need to model human beings in all of our mind-blowing complexity. We only need to model those attributes of a person that are required for the application to do its intended work.
Let us now suppose that we want to give our Person class a new capability… the ability to introduce itself. . Before we can do that though, we need to revisit our class definition. The line that reads “attr_accessor :first_name” is Ruby’s rather kludgy way of declaring a property. It is what makes lines 13-15 above possible. It declares a variable called @first_name. The @ prefix means that this is an instance variable which is visible from anywhere within the class. The name for this visibility is called scope. This concept will become clearer when we add some methods.
To declare a method in Ruby, we begin by using the keyword “def”, followed by the method name. In our case: def say_introduction. We then enter as many lines of code as are required to implement the desired behavior. Finally, we end the method definition with the keyword “end”. Notice that the same keyword, “end” is used to end both the class definition and method definitions.
Notice that we have moved the puts instruction from outside the class to inside the class. Now, when we want to print a greeting, we only need to call the method say_introduction on the object (referenced by a variable, a).
If we save our code in a file called “say_hello.rb” and run it using the ruby command, the output will appear as it does below:
Recall earlier when we described some behaviors as needing a bit more input, such as eating requires food? Also recall that we had a name for the additional information… argument or parameter.
We’re going to add a new method (behavior) to the Person class. We’re going to add the ability to say the greeting to a specific person. Look at the updated class definition below. We’ve created a new method, say_introduction_to, which expects a parameter to be passed to it. If you look at line 27, we do exactly that, passing to it the string “Joe”.
Let’s run this code and see the results below:
This tutorial is written for the person who is an absolute beginner to programming. I will make frequent analogies to real-world things, outside of programming as a means to illustrate important programming concepts in general and object-oriented concepts in particular. Too often, tutorials for a language assume a working knowledge of programming in another language. That is not the case here. If you’ve never written a line of code in your life, you should feel completely comfortable with these lessons.
This course assumes you already have Ruby installed on your computer.
Classes and Objects
Before we can get into Rails, we really need to understand Ruby. There are those who disagree with this statement, but it is helpful, in my opinion, to understand where Ruby, the language, ends and Rails, the framework, begins. We need to get over one other MAJOR mental concept.. We need to understand classes… and objects.
Ruby is what is called an object-oriented language. As such, classes and objects are very central to the design and use of the language. The beginner might ask “What’s a class? What’s an object??”
An analogy (or two) is in order. Consider a cookie cutter. A cookie cutter is a kind of specification, or blueprint for.. cookies. Given cookie dough and a Christmas tree-shaped cookie cutter, one could make zero, one or many cookies using the cookie cutter. In some respects, the cookies will have certain characteristics that will always be the same across all cookies made from it, namely, the outline/shape. They will all be identical. However, it is also possible to use different kinds of dough, sprinkles on some cookies, not others, frosting on some, not others. In this regard, each individual cookie can differ from all the other cookies. In programming terms, we call each cookie an object… and the cookie cutter is the class (blueprint) used to create the objects. Another term you should learn is instance. An instance is merely an individual cookie. Multiple cookies are referred to as “instances”.
The “things” that can vary between objects are called properties. Cookies are a little sloppy. Let’s consider a better example. An automobile assembly line…. and the cars produced by it. Of course, the assembly line is like a “class” and the cars produced are “objects” or “instances of the class” (these are just words.. don’t get too hung up on them….).
Some cars have black interiors, others blue, still others tan. So, “interior color” is something that can vary between vehicles… therefore, interior color is considered a property of the class. So is engine size, so is exterior color, VIN, etc. While every car produced by the assembly line is largely similar, each “instance” can vary in many ways.
Let’s take a look at how this might look in Ruby code:
In the code above, the line that reads “# Class definition: Person” is a special kind of statement in Ruby.. it is called a comment. A comment does not actually do anything… rather it serves as additional information, beyond what merely reading the code alone provides. Why write a comment in our code? Because in the world of professional programming, chances are very good that someday a programmer other than the programmer who originally wrote this code will have to make changes to it. Comments are merely a way of leaving “notes” behind for the next programmer, as two what the original author was thinking at the time they wrote the code.
The next line, “class Person” begins our declaration of the class we’ve decided to name Person. The line that reads “end” ends our class definition. All the lines between “class” and “end” constitute our specification of what we want to the class to do. For now, we’re going to ignore the lines between “class” and “end”, but rest assured they will be thoroughly explained.
Now that we’ve declared or defined a class.. it’s time to use it. Let’s create three instances (objects) of type Person.
This is an important piece of vernacular to get your head around: We create objects of a type, and we say that as “creating objects of type x” (whatever class x happens to be).
Now, you may be asking “What’s up with the letters a, b and c as well as the equals sign in the above examples. Also, what’s up with “.new” at the end of Person? Worthy questions all. Let’s take just one of these lines and examine it in detail.
In the code above, “Person.new” is our way of telling the Ruby interpreter we want to create a new instance of the Person class. More about the interpreter later. Presumably once we create the new instance, we’ll want to do something with it. Just about the only way we can do something with an object is to save a reference to it in something called a variable. A variable is a name we declare simply by typing it and assigning something to it. So then, the code above does three things: 1) creates a new instance of the Person class, 2) declares a variable named “a” and 3) assigns a reference to the newly created Person instance to our variable “a”.