Using Objects - Computer Science Programming Basics in Ruby (2013)

Computer Science Programming Basics in Ruby (2013)

Chapter 8. Using Objects

IN THIS CHAPTER

§ Objects

§ Built-in objects

8.1 Introduction

In Chapter 6, we discussed the concept of arrays and hashes, additional structures that can be used to store data. In this and the following two chapters, we discuss objects.

8.2 Objects and Built-in Objects

So far, we have been writing code that is procedural in nature; that is, code whose logical flow starts at the top and works its way to the bottom. Any computer program can be written in a procedural manner. However, when code gets long, it becomes difficult to debug and maintain. It also becomes redundant and dangerous to write the same code over and over. The object-oriented approach was created for dealing with these very issues. To switch to objects, you must understand why they are useful in the first place.

Imagine a product as complex as Microsoft Word. To produce it, a team of Microsoft programmers had to write millions of lines of code, with hundreds of people working on the code at the same time. To support simultaneous development, the code was segmented by functionality. Understanding how such complex products get subdivided into manageable pieces requires that we first understand the building blocks of such code. These building blocks in Ruby are classes that define objects.

8.2.1 Objects

Objects and object-oriented programming simplify the implementation of large programs. If you work on a program by yourself, it is up to you to organize your work. If you work with 100 other programmers, then everything must be nicely compartmentalized; otherwise, each programmer will constantly step on the other programmers’ toes. There is nothing worse than getting your piece of a program to work and finding out that you inadvertently broke someone else’s.

GEM OF WISDOM

Ruby is a truly object-oriented language, and that is one reason we picked it for this book. Objects usually correspond to entities that exist in the real world. They encapsulate values and support actions as well. While a variable might have a value 5, an object named airplane might have one value of Boeing 747 and another value of current location. Also, airplane can have an action that says fly() that might change its current location based on how far it has flown.

If you and your friend decide to work on a project together, you can easily run into trouble. Imagine if your friend makes a variable called x and manipulates it. You remain unaware of this changing of value. So later on in the code, you likewise decide to use a variable called x. Your piece of code and your friend’s piece of code both work on their own, but when you integrate them, strange problems occur.

Objects are designed to separate key activities in a program so that once you get something to work, you need not constantly worry about accidentally breaking it when you make new objects. The activities are essentially isolated from one another. They can communicate information without the need to know how it is produced and what the specifics of the implementation are. For example, a programmer might build an object called TicTacToe when making a tic-tac-toe board game. Once the part of the program that draws the board works, everyone can just communicate with that object in a way that ensures that no one steps on another programmer’s toes.

Objects enable programs to be compartmentalized so that programmers can work at the same time without fear of running over one another. Consider a construction crew building a house. Someone painting one room does not constantly check on the work of someone who is painting another room. This is because the rooms are compartmentalized—they have walls and ceilings that keep paint from dripping from one room to the other. However, two painters working in the same room must always be in constant communication to be effective and efficient. For example, if they were not communicating, it would be possible that one painter could drip paint on the other or paint the worker into a corner.

Objects are isolated pieces of code that have their own private chunks of data and private actions that can be performed with that data. The actions that an object may perform are referred to as methods. Object-oriented programming tries to create the most logical separation between pieces of code.

8.2.2 Built-in Objects

Without realizing it, you have been using objects since the moment you began to program anything in Ruby. In Chapter 3, you began using objects when you started using variables; you just did not have to think about it. In fact, everything in Ruby is an object, and this section will discuss some of the more common objects you will use.

An application programming interface, or API, is an interface provided to the programmer to allow the use of certain functionality without knowing the specifics of the implementation. When you downloaded the Ruby interpreter to your hard drive, you probably downloaded a copy of Ruby’s API documentation with it, but in case you did not, it is available online. If you visit this site, you will notice it has three headings: files, classes, and methods. For now, we will focus on classes.

A class defines the characteristics and behaviors of an object. It contains the variables and the code necessary to implement the operations of the object, usually called methods. If you look through the list of classes, you will see there are many. However, you have already used a few of them. Some classes you may have already used are the array, Fixnum, float, and string classes. While there are many more classes than these, it is not required that you know what they do or what they consist of. However, it is required that you know how to use them when the time comes.

For any class, all the supported methods for the class are provided.

For example, the string class (see Figures 8-1 and 8-2) has a length method, str.length => integer. This means that if we call the string’s length method, it will return an integer. The next part is simply a description of the method, and it does what one would expect a length method to do. The following is an example of using this method:

irb(main):001:0> "hello".length

=> 5

Simply put, we call the string class method length on the string object “hello,” and we get back the number of characters in “hello,” which is 5. This is a simple example of calling, or using, a method. However, calling a method is not always this simple. Let’s look at another example of a method from the string class.

String API documentation

Figure 8-1. String API documentation

String’s method: length

Figure 8-2. String’s method: length

The example method in Figure 8-3 is significantly more difficult. It shows multiple ways to call the method index, along with the results returned when the method is called. By looking at the description of the method taken from the actual Ruby documentation website and written on top of the example calls, you may be able to decipher how calling this method works, but it uses concepts we have not yet discussed. The main concept here is that this method needs some type of outside data to work; supplying this outside data to a method while calling it is known as parameter passing.

String’s method: index

Figure 8-3. String’s method: index

8.2.3 Parameter Passing

Looking at the list of built-in methods, you will see that the syntax for some of them requires a variable in parentheses; these variables are called parameters. When using built-in methods with parameters, you are sending the value of the variable to the method to be manipulated. Consider the imaginary method called multiplier in Example 8-1.

Example 8-1. Parameter passing

1 x = 3

2 y = x.multiplier(4)

3 puts "The number is: " + y.to_s

Line 1 defines the variable x to be 3. The next line assigns a value to y by calling our imaginary method multiplier and passing the value of 4 as a parameter. If we looked at the output of this method, it would show:

The number is: 12

By looking at this, you can assume that the method multiplies the value of the parameter by a certain value. If we want to find out what the multiplier method really does, we can change the value of the parameter to 5. After doing this, the observed output is:

The number is: 15

You can now conclude that the multiplier method multiplies the value of the parameter by the value of x. The key concept of parameters in methods is that it does not matter what value is being passed; an output is generated using the same operations within the method every time. Think of the method as a black box, as depicted in Figure 8-4.

Black box for multiplier method

Figure 8-4. Black box for multiplier method

The system has an input z, an output y, and a black box. The input z is sent to the black box, which manipulates the variable and then outputs it as y. We do not know, nor do we care, what happens inside the black box. The only thing that matters is the resultant output.

Now let’s look at an example using the actual Ruby built-in method called split. This method is used with strings and splits the strings into array elements based on the parameter passed. In this case, this will be the delimiter. Observe the example in Example 8-2.

Example 8-2. Split example 1

1 my_string = "Good;day;sir!"

2 arr = my_string.split(";")

3 puts arr

4

5 # The following array is created:

6 # arr[0]: "Good"

7 # arr[1]: "day"

8 # arr[2]: "sir!"

§ Line 1 defines a string object with the value “Good;day;sir!”

§ Line 2 calls the built-in method split with a semicolon as the parameter.

§ Line 3 outputs the values of my_array.

After executing the code, the array shown in lines 6–8 will be created, and the output will be the following:

$ ruby split_1.rb

Good

day

sir!

As you can see, the split method has created an array with three indices based on the parameter passed (in this case, the semicolon). Now, what if we changed the parameter of the split method to something else, as shown in Example 8-3?

Example 8-3. Split example 2

1 my_string = "Good;day;sir!"

2 arr = my_string.split("a")

3 puts arr

4

5 # The following array is created:

6 # arr[0]: "Good;d"

7 # arr[1]: "y;sir!"

Now the split method will perform the same operation, but instead of splitting the string object based on the semicolon, it will split the string into array values based on the new parameter. The resultant array is once again shown in the comments in lines 6 and 7, with the following output:

$ ruby split_2.rb

Good;d

y;sir!

The split method has created an array with two elements based on the parameter a. You can see that no matter what the input is, the program will always perform the same operation based on the parameter passed. It does not matter what the input is or what is inside the method; the split method will create arrays splitting your string object wherever there is an occurrence of the indicated parameter.

An astute reader may wonder what would happen if the chosen parameter for split did not exist in the string, my_string. In this case, an array of one element is returned, with the first element containing my_string. The code in Example 8-4 illustrates this.

The output follows from the array’s structure, as shown in line 6.

Example 8-4. Split example 3

1 my_string = "Good;day;sir!"

2 arr = my_string.split("z")

3 puts arr

4

5 # The following array is created:

6 # arr[0]: "Good;day;sir!"

$ ruby split_3.rb

Good;day;sir!

8.3 Summary

Objects and their corresponding methods are the building blocks of many of today’s software systems. For all object-oriented programming languages, some objects and methods are predefined, and those are always specified in the language manuals.

In that light, we introduced objects, explained built-in objects, and discussed parameter passing, a mechanism to transfer information in and out of objects.

8.3.1 Key Concepts

§ Classes define the characteristics and behaviors of objects belonging to the class.

§ Objects are instantiations of a class. They have a name and possess all the properties of the class, namely, the variables and the methods.

§ The application user interface, or API, is an interface used to communicate with some underlying functionality.

8.3.2 Key Definitions

§ Object: An isolated piece of code that has its own actions and data.

§ Method: The action that an object may perform.

§ API: An interface provided to the programmer to allow the use of certain functionality without knowing the specifics of the implementation.

§ Class: Construct that contains the definition of an object template and the implementation of the methods.

§ Parameter passing: The passing of data to a method within an object.

8.4 Exercises

1. Provide code using the split method to separate the following string into individual words and then display them:

my_string = "Roses!are!red!Violets!are!blue"

2. You are programming part of the sign-up procedure for an online computer game. Write a program that prompts the user to enter his or her user ID and password and enforces the following restrictions:

a. User IDs and passwords must be at least seven characters in length.

b. Passwords must contain at least one of each of the following: uppercase character, lowercase character, number, and symbol.

Hint: use the documentation for the string class.

3. Write a program that prompts the user for three words and then outputs the total and average number of characters in the three words.

4. What would result if you were to type the following into irb?

5. irb(main):001:0> "12345".length

6. irb(main):002:0> "12345" * 5

7. irb(main):003:0> "12345".index(2)

8. irb(main):004:0> "12345".index(0)

9. irb(main):005:0> "12345".index(1)

irb(main):006:0> "12345".index(5)

10.What does it mean to pass a parameter to a method? What happens when a parameter is passed to a method?

11.Write a function multiplier that multiplies the value passed to it by x. Have the function ask the user for the value of x.