Objects and Methods

An introduction to the nouns and verbs of Ruby, which we'll cover in even greater depth in upcoming lessons.

Scroll down...

Content

Resources

Comments

In this lesson, we'll cover the basic concepts of working with objects and methods as well as some things about classes in Ruby. These are all topics we'll dive deeper into in later lessons, so consider this a crash course.

Objects

"Everything in Ruby is an Object" is something you'll hear rather frequently. "Pretty much everything else is a method" could also be said. The goal here is for you to see the Matrix... that everything in Ruby is an Object, every object has a class, and being a part of that class gives the object lots of cool methods that it can use to ask questions or do things. Being incredibly object-oriented gives Ruby lots of power and makes your life easier.

Think of every "thing" in Ruby as a having more than meets the eye. The number 12 is more than just a number... It's an object and Ruby lets you do all kinds of interesting things to it like adding and multiplying and asking it questions like:

> 12.class
#=> Fixnum
> 12+3
#=> 15

Methods

Ruby gives all objects a bunch of neat methods. If you ever want to know what an object's methods are, just use the methods method! Asking 12345.methods in IRB will return a whole bunch of methods that you can try out on the number 12345.

You'll also see that the basic operators like + and - and / are all methods too (they're included in that list). You can call them using the dot, dot and parenthesis, or just "naked" like you normaly would:

> 1+2  # the "normal" way
#=> 3 
> 1.+2  # another option
#=> 3
> 1.+(2) # explicitly speaking...
#=> 3

You wouldn't ever use the second or third option, but remembering that EVERYTHING in Ruby is an object or a method is a useful mental model to have.

It's also useful to note that the parentheses around the argument for the method are optional (as you see in the example above). This makes a lot of beginners uncomfortable (especially those coming from strict languages), but you'll get used to it. Remember -- just because it doesn't have parentheses doesn't mean it's not a method!

True / False Questions

Some methods ask true/false questions, and are usually named with a question mark at the end like is_a?, which asks whether an object is a type of something else, for example:

> 1.is_a?(Integer)
#=> true
"hihi".is_a?(Integer)
#=> false

You'll get used to the question-mark-for-questions naming convention.

Reflection

Methods like is_a?, which tell you something about the object itself, are called Reflection Methods (as in, "the object quietly reflected on its nature and told me that it is indeed an Integer"). The method class was another one we saw, where the object will tell you what class it is:

> "howdy!".class
#=> String

Back to Method Basics

What is a method? A method is just a function or a black box. You put in the thing on the left with some arguments to the right and it spits out the result afterward. Every method returns something, even if it's just nil.

Some methods are more useful for their Side Effects than the thing they actually return, like puts. That's why when you say puts "hi" in IRB, you'll see a little => nil down below... the method prints out your string as a "side effect" and then returns nil after it's done:

> puts "Howdy!"
Howdy!
#=> nil

When you write your own methods, if you forget to think about the return statement, sometimes you'll get some weird behavior so always think about what's going in and what's coming out of a method.

Arguments

Methods can take arguments too, which are included in parentheses to the right of the method name. As we said above, these parentheses are optional, so you could say either of these:

> puts "hi"
hi
#=> nil
> puts("hi")
hi
#=> nil

For another example, you can take an arithmetic expression and write it the long way like we described before, which makes each method's arguments much clearer:

> 1+2==3  # Short form
#=> true
> 1.+(2).==(3)  # Long form (never actually used!)
#=> true

...but why would you ever write it out the long way?

That's why Ruby is great -- there's a shorter and simpler way for everything.

Method Chaining

The addition example above also shows Method Chaining, which is when you stick a bunch of methods onto each other. It behaves like you'd expect -- evaluate the thing on the left first, pass whatever it returns to the method on the right and keep going. So 1+2==3 first evaluates 1+2 to be 3 and then evaluates 3==3 which is true.

This is great because it lets you take what would normally be many lines of code and combine them into one elegant expression.

Bang Methods

Bang Methods are finished with an exclamation point ! like sort!, and they actually modify the original object. The exclamation point lets you know you're in dangerous territory.

When you run a normal method in IRB, it will normally output whatever the method returns but it preserves the original object. Bang methods save over the original object (they are "destructive"):

> my_numbers = [1,5,3,2]
#=> [1, 5, 3, 2]
> my_numbers.sort
#=> [1, 2, 3, 5]
> my_numbers
#=> [1, 5, 3, 2]    # still unsorted
> my_numbers.sort!
#=> [1, 2, 3, 5]
> my_numbers
#=> [1, 2, 3, 5]    # overwrote the my_numbers object!

Writing Your Own Methods

To Write Your Own Methods, just use the syntax def methodname(argument1, argument2, argumentN), though the parentheses around the arguments are optional. The method will return ("spit out") either whatever follows the return statement or the result of the last piece of code that was evaluated (an Implicit Return statement). You call the inputs by whatever name you defined them at the top.

You can write methods in IRB... it will let you use multiple lines if it detects that you have unfinished business (a def without an end or unclosed parentheses):

> # IRB
> def speak(words)  # Create the method first
>    puts words
>    return "fuzzy-wuzzy!"
> end
#=> :speak          # Ignore this
> speak("hello!")   # Then run the method
hello!
#=> "fuzzy-wuzzy!"  # Return value

Default Inputs

What if you want to assume that the input to a method is some default value if there otherwise hasn't been one supplied? That's easy, just specify the Default Input by assigning the input variable to something in the parentheses:

> def speak(words="shhhhh")
>     puts words
> end              # implicitly returns same as puts does
#=> :speak         # ignore this
> speak            # no input
shhhhh
#=> nil
> speak("this is an input")
this is an input
#=> nil

Classes

Let's answer the question, "Where did all those methods come from?" Classes are like umbrellas that let us give an object general behaviors just based on what it is.

An object is an instance of a class -- you (yes, you) are an instance of the Person class. There are lots of behaviors (methods) that you can do just by virtue of being a Person... you can laugh, jump, speak("hello").

This is really useful in programming because you often need to create lots of instances of something and it's silly to have to rewrite all the methods you want all of them to have anyway, so you write them at the class level and all the instances get to use them.

Everything in Ruby has some sort of class:

3.class #=> Fixnum
3.0.class #=> Float
"Hello".class #=> String
'hi'.class #=> String

# Special values are objects too  
nil.class #=> NilClass
true.class #=> TrueClass
false.class #=> FalseClass

Classes are the secret sauce of object-oriented programming so we'll spend a lot more time covering them in future lessons. This is just a teaser.

Inheritance

Individual instances of a class get to inherit the behaviors of the class they belong to. Inheritance works for classes too! Your class Person has lots of methods but many of them are inherited just by virtue of you also being a Mammal or even just a LivingThing You get to use all the methods of your ancestor classes.

An interesting exercise to try in Ruby is to use the method superclass to ask a class what its parent is. If you just keep on going and going, you'll see that everything eventually inherits from BasicObject, which originates most of the methods you have access to in the original object:

> 1.class.superclass.superclass.superclass
=> BasicObject
> BasicObject.methods
=> # giant list of methods

Additional Points of Interest

The following are more points of interest than things you really need to know but...

Fishing for Methods

Running the methods method on a class only returns the class methods, whereas running instance_methods on it will return all methods available to any instance of that class. For example:

> String.methods.count
#=> 100  # All the class methods on String
> "Hello".methods.count
#=> 164  # Also with additional instance methods
> String.instance_methods.count
#=> 164  # Yep, the world makes sense.  For now.

Object IDs

Every object is really just a pointer to somewhere in your computer's memory where Ruby can find the actual object (though it's slightly different for FixNums, Booleans and nil).

> "I am a string".object_id
#=> 70226360259380  # Yours will differ
> 1.object_id
#=> 3  # Yours will be the same because integers are special
> str = "another string"
#=> "another string"
> str.object_id
#=> 70226376922740  # Yours will differ

Use the object_id method to see an object's id, and this can be useful if you're running into odd errors where you thought you were modifying and object but it's not changing. If you debug and look at the IDs along the way, you may find that you're actually only modifying a COPY of that object. We'll get into the specifics of when you might be modifying a copy of an object (e.g. inside a block) instead of the object itself.



Sign up to track your progress for free

There are ( ) additional resources for this lesson. Check them out!

Sorry, comments aren't active just yet!

Next Lesson: Strings and Symbols