Methods
In this lesson, we're going to deconstruct what methods are, examine their behavior, and learn how to use them.
Introduction
In Ruby, methods are where all the action happens!
You will often find yourself writing code that does the same thing in different places in your program. Wouldn't it be great if there was a way to reuse the same code over and over again without having to write it all out each time? This is what methods are for! Methods allow you to name sections of your code and then run that code anywhere in your program as many times as you need just by calling that name.
This concept allows for what programmers refer to as the DRY approach to programming: Don't Repeat Yourself. Recycling sections of code instead of repeating them throughout your programs can make your program more readable and manageable.
As you read more about Ruby methods, you'll notice that the terms "methods" and "functions" are often used interchangeably. What's the difference? According to The Ruby Programming Language book:
Many languages distinguish between functions, which have no associated object, and methods, which are invoked on a receiver object. Because Ruby is a purely object-oriented language, all methods are true methods and are associated with at least one object.
Basically, because everything in Ruby is an object, Ruby only has methods, not functions. With that established, we know that when we're talking about Ruby, "methods" and "functions" refer to the same thing.
In this lesson, we're going to deconstruct what methods are, examine their behavior, and learn how to use them.
Learning outcomes
By the end of this lesson, you should be able to do the following:
Explain how to create and call a new method.
Explain how to pass variables to a method and how to define default parameters.
Describe the differences between implicit return and explicit return.
Explain what it means to chain methods together and how to do it.
Explain what predicate methods are and how to use one.
Explain what bang methods are and how to use one.
Built-in methods
One of Ruby's great advantages for new programmers is its large number of built-in methods. You've been using many of them already, probably without even realizing it. Over the course of your learning so far, you have modified strings and other objects in various ways. For example, the #times
and #upto
loops that you learned about in the Loops lesson are both methods that are included as part of Ruby's Integer
class.
If you're wondering about all of the pound signs (#
), they're just the convention for writing out Ruby instance methods. We can use them to write out the full name of an instance method, e.g., Integer#upto
, or just the method name, e.g., #upto
, depending on the context. Note that in the development world, you shouldn't call these "hashtags". If you want to be super awesome, though, you can call them "octothorpes". That word is totally trending.
Methods are typically called by adding .method_name
after an instance of the object that contains that method.
In this case, #reverse
is a built-in method for String objects.
However, there are also some built-in methods that Ruby makes globally accessible, such as print
and puts
. These methods are called with just their name and any arguments. (If you're super curious, these methods are made globally available by the Kernel module through the Object class, but that's far more than you need to know right now.)
It's worth noting that in most languages, arguments are passed to methods by wrapping them in parentheses ()
. In Ruby, however, the parentheses are generally optional. We could rewrite the above code as puts("anything")
, which Ruby would interpret in the same way.
Creating a method
You can create your own custom methods in Ruby using the following syntax:
Let's break this example down:
def
is a built-in keyword that tells Ruby that this is the start of a method definition.my_name
is the name of your new method. You can name your methods almost anything you want, but there are some constraints and conventions, which are described in the next section."Joe Smith"
is the code inside the method body. All of the logic for your method is contained in the indented lines of the method body. This particular method returns a string when the method is called.end
is a built-in keyword that tells Ruby that this is the end of the method definition.To call the method, you simply need to use its name, as shown in the last line of the example.
Method names
As mentioned above, you can name your methods almost anything you want, but you shouldn't pick names haphazardly. There are certain conventions that are recommended in order to improve the readability and maintainability of your code.
Your method names can use numbers, capital letters, lowercase letters, and the special characters _
, ?
, !
, and =
. Just like with variable names in Ruby, the convention for a method name with multiple words is to use snake_case, separating words with underscores.
Here are some things you are not allowed to do with your method names:
You cannot name your method one of Ruby's approximately 40 reserved words, such as
end
,while
, orfor
. Checkout the full list here.You cannot use any symbols other than
_
,?
,!
, and=
.You cannot use
?
,!
, or=
anywhere other than at the end of the name.You cannot begin a method name with a number.
Here are some examples of valid and invalid method names:
Can you tell why some of these names are invalid?
In general, short but descriptive is the name of the naming game. You want to be able to tell what a method is expected to do based on its name, so please don't name your method do_stuff
.
If your method does so many things that you feel it requires a very long name, then your method should probably be broken up into several smaller and simpler methods. Ideally, each method should do only one thing. This practice will pay dividends down the road in terms of readability, scalability, and maintainability. (It also makes testing your code a lot easier, which will be covered in a later lesson.)
Parameters and arguments
Of course, not all methods are as simplistic as the my_name
example method above. After all, what good are methods if you can't interact with them? When you want to return something other than a fixed result, you need to give your methods parameters. Parameters are variables that your method will receive when it is called. You can have more meaningful and useful interactions with your methods by using parameters to make them more versatile.
In this example, name
is a parameter that the greet
method uses to return a more specific greeting. The method was called with the argument "John"
, which returns the string "Hello John!"
If you're wondering what the differences are between an argument and a parameter, parameters act as placeholder variables in the template of your method, whereas arguments are the actual variables that get passed to the method when it is called. Thus, in the example above, name
is a parameter and "John"
is an argument. The two terms are commonly used interchangeably, though, so don't worry too much about this distinction.
Default parameters
What if you don't always want to provide arguments for each parameter that your method accepts? That's where default parameters can be useful. Going back to our simple example above, what happens if we don't know the person's name? We can change our greet
method to use a default name
of "stranger":
What methods return
An important detail that a programmer must learn is understanding what your methods return. Having a good understanding of what your methods are returning is an important part of debugging your code when things don't behave as expected.
How do we tell our methods what to return? Let's revisit our my_name
example method:
Our my_name
method returns "Joe Smith". This may seem obvious because it's the only thing inside the method. In most languages, however, such a method would not return anything because it does not have an explicit return statement, which is a statement that starts with the return
keyword. The above example could just as easily be written with an explicit return:
Ruby is one of the few languages that offers implicit return for methods, which means that a Ruby method will return the last expression that was evaluated even without the return
keyword. The last expression that was evaluated may or may not be the last line in the code, as you can see in the following example:
Here, the method's return is dependent on the result of the if
condition. If the argument is an even number, the expression inside the else
statement never gets evaluated, so the even_odd
method returns "That is an even number."
Even though Ruby offers the ease of using implicit returns, explicit returns still have a place in Ruby code. An explicit return (using the keyword return
) essentially tells Ruby, "This is the last expression you should evaluate." This example shows how using return
stops the method from continuing:
For example, an explicit return can be useful when you want to write a method that checks for input errors before continuing.
Now, try removing the explicit return
from the method above. Does the method return what you expected?
Difference between puts and return
A common source of confusion for new programmers is the difference between puts
and return
.
puts
is a method that prints whatever argument you pass it to the console.return
is the final output of a method that you can use in other places throughout your code.
For example, we can write a method that calculates the square of a number and then puts
the output to the console.
This method only prints the value that it calculated to the console, but it doesn't return that value. If we then write x = puts_squared(20)
, the method will print 400
in the console, but the variable x
will be assigned a value of nil
. (If you need a refresher on this, go back and review the Ruby Input and Output lesson.)
Now, let's write the same method but with an implicit return instead of puts
. (Using an explicit return will act exactly the same in this example.)
When we run the return_squared
method, it won't print any output to the console. Instead, it will return
the result in a way that allows it to be used in the rest of your code. We can save the output of running this method in a variable (x
in the code below) and use that variable in a variety of ways. If we would still like to see the result of the method in the console, we can puts
that variable to the console using string interpolation.
Chaining methods
One of the magical properties of methods that allows you to write very concise code is being able to chain methods together. This can be done using Ruby's built-in methods or with methods that you create.
Chaining methods together like this effectively has each method call build off of the outcome of the previous method in the chain. The process that takes place essentially produces the following steps:
Predicate methods
You will sometimes encounter built-in Ruby methods that have a question mark (?
) at the end of their name, such as even?
, odd?
, or between?
. These are all predicate methods, which is a naming convention that Ruby uses for methods that return a Boolean, that is, they return either true
or false
.
You can also create your own method with a ?
at the end of its name to indicate that it returns a Boolean. Ruby doesn't enforce this naming convention, but you will thank yourself later for following this guideline.
Bang methods
Observe the example below:
What gives? I thought we downcased that thing! So why was it back to all uppercase when we called it again?
When we call a method on an object, such as our whisper
string above, it does not modify the original value of that object. A general rule in programming is that you do not want your methods to overwrite the objects that you call them on. This protects you from irreversibly overwriting your data by accident. You are able to overwrite your data by explicitly re-assigning a variable (such as whisper = whisper.downcase
). Another way to do this type of reassignment is with bang methods, which are denoted with an exclamation mark (!
) at the end of the method name.
By adding a !
to the end of your method, you indicate that this method performs its action and simultaneously overwrites the value of the original object with the result.
Writing whisper.downcase!
is the equivalent of writing whisper = whisper.downcase
.
Assignment
For a good introduction to all the different concepts related to methods, read the Methods chapter from Launch School's Introduction to Programming with Ruby. Make sure to do the exercises at the end of the chapter too!
To get a different take, read the part of the Objects section that discusses Methods from Ruby Monsta's Ruby for Beginners.
For more depth on how you can write your own methods, read the section on Writing Methods from Ruby Monsta's Ruby for Beginners.
Complete the method exercises from the ruby-exercises repo that you previously cloned.
Additional resources
This section contains helpful links to other content. It isn't required, so consider it supplemental for if you need to dive deeper into something.
For a deeper look at methods, read the Methods chapter from the Bastards Book of Ruby. Try to complete the exercises throughout the chapter.
For more discussion on the subtle differences between methods and functions and how they can differ between programming languages, here is a handy explanation on Stack Overflow.
Knowledge check
This section contains questions for you to check your understanding of this lesson. If you're having trouble answering the questions below on your own, review the material above to find the answer.
How would you create your own method?
How would you call your new method?
How do you pass variables to your method?
How do you define default parameters for your method?
What is the difference between an explicit return and an implicit return?
What is the difference between
puts
andreturn
?How do you chain multiple methods together?
Give an example of a valid method name and an invalid method name.
What is snake case?
What are some of Ruby's reserved words?
What do you call a method that returns
true
orfalse
? What is their naming convention?What do bang methods do? What is their naming convention?
Last updated