Methods
We’ll be doing some work in replit today. Find your Mod 0 Lessons Repl from the Data Types lesson so you can use it in today’s lesson. It might be helpful to comment out the puts/prints code from that previous lesson.
Learning Goals
- Explain the purpose of methods
- Use built-in methods on appropriate objects based on data type
- Define and call methods in Ruby
- Use and explain the flow of data with arguments and parameters
- Describe the purpose of a return value
Vocabulary
- method
- define
- execute or call
- return
- parameter
- argument
Methods
A Method is a package of instructions. Once a method is defined, it can be used as many times as needed. Ruby provides many built-in methods that developers can use.
Defining Our Own Methods
There are many methods that are built into the Ruby language. Those are great and you will use them regularly as a developer (and you’ll explore them later today!). There will also be times when you need to write your own method to solve a unique problem in the application you are building or maintaining.
Syntax for Defining a Method
To define our own method, we’ll use the following guidelines:
- The
def
andend
keywords act like bookends for the code block. - Following the keyword
def
, we assign our method a name. It’s best if the name describes what the method does. - The code block is indented and contains all of the “instructions” for what the method should do when it is called.
- The value on the last line of the code block is the data that the method will return when it is called.
In the method below, the code block has only one line, but it’s important to note that there could be many lines of code within the code block, describing the steps that a method should follow. You can even include other things we’ve learned like conditionals and built-in methods within your code block.
# method definition
def greet_a_texan
"Howdy, partner!"
end
After defining a method, nothing will appear to happen. The interpreter that reads the Ruby code will read it, and be aware of that set of instructions, but it won’t carry out those instructions until it is explicitly told to do so.
Syntax for Calling a Method
To instruct the interpreter to carry out the instructions in a method, the developer must write code to call or execute that method. Simply writing the name of the method, greet_a_texan
in this example, calls or executes the method. When we call this method by writing the name of the method, it triggers the “instructions” held within the code block of that method. Now, this method by itself only returns the string “Howdy, partner!” - we still need to use a puts
command to see that return value in the console.
# method call
greet_a_texan
Naming Conventions
Since methods provide action to a program, they should be named accordingly; it’s best practice to start them with a verb. Like variables, Ruby methods should use snake_case
when they involve more than one word and should be written carefully to describe their role specifically without being overly verbose.
Examples of method names that follow best practices:
get_user_input
display_followers
add_two_numbers
find_longest_name
In the example above, the developer chose the method name of greet_a_texan
. Method names should usually include verbs, since methods do something. The definition just tells the program that it’s a set of directions ready to be followed; the method call is what makes the code in the method execute, or follow the packaged directions. You can call a method as many times as you want, once it’s been defined!
A Method Metaphor
Often, we want to use a method to perform an action on or with a piece of data. Think back to those built-in methods. We didn’t simply call the odd?
method by itself. We called it on an Integer object and it returned a Boolean value. We can do the same thing with the methods we define. Think of your method like a machine with inputs and outputs.
If this were a cookie machine, for example, the machine would take in all of the raw ingredients (eggs, flour, sugar, etc.) and perform some steps to make the cookies:
- Mix ingredients to make dough
- Place dough balls on a baking sheet
- Bake at 350 degrees for 10 minutes
- Let cookies cool
- Serve the cookies on a plate
We can imagine that our cookie machine would do all of those steps and then give us back freshly baked, warm cookies!
Let’s expand this example to any kind of machine. We give the machine the raw materials, it does something with those materials, and then returns the final product. This is very similar to what we are doing with our own methods. We give the method some piece of data or information (or even multiple pieces of information) and then the method does something with that information and spits out a return value.
Think About It
Look at the method call below and make a guess about how this might be different from the previous method example.
greet_a_texan("Kaitlyn") # => "Howdy, Kaitlyn!"
Without possibly having all the information about Ruby syntax, you probably made some connection as to what might be happening with the previous code snippet. The greet_a_texan
method was called, but this time, we were able to dynamically change the name of the person we were greeting!
Arguments & Parameters
Arguments are the technical term for the inputs to a method such as the String that was provided in the parenthesis after the method name in the previous example. As developers, we have the control to name the parameters, or placeholders, for the data that will be passed in. Those names should follow variable name conventions and be concise, yet descriptive. The number of arguments passed in should match the number of parameters declared.
# name is a parameter
def greet_a_texan(name)
"Howdy, #{name}!"
end
# "Kaitlyn" is the argument for this method call
puts greet_a_texan("Kaitlyn")
# => "Howdy, Kaitlyn!"
# "Brian" is the argument for this method call
puts greet_a_texan("Brian")
# => "Howdy, Brian!"
Note: You’ll notice that we are using the puts
command in front of the method call this time. This allows us to also see the return value of the greet_a_texan
method printed to the console, but it is not necessary. The code greet_a_texan("Kaitlyn")
by itself does return the string “Howdy, Kaitlyn!”, but if we want to see it printed in the console, we will need to use puts
or print
along with the method call.
Practice
- Write a method named
greet_an_animal
. This method should declare one parameter, a String, and when called, should return a string with a greeting for the specific animal that was passed in as an argument. - Write a method named
multiply
. This method should declare two parameters, both Integers, and when called, should return the product of the two Integers. Call the method several times with different arguments and run the code to ensure it's working as expected.
Return Values
A return value is either:
- Defined implicity: By default, the last line of code automatically becomes the return value of the method.
OR - Defined explicitly: By using the
return
keyword, we can also specify the return value of the method.
In the add
example below, the return value is an Integer or Float, based on what values were passed in as arguments. If 2 and 3 are passed in, the return value is 5. This is called an implicit return. Ruby automatically returns the value of the last expression in a method if no return
is present. For this reason, if we want to return the value of the last expression in a method, we usually do not use the return
keyword, as it is considered redundant and unnecessary.
def add(num1, num2)
num1 + num2
end
add(2, 3)
# => 5 (return value is 5 since that's the sum of 2+3, and on the last line of the method)
In the subtract
example below, the return value will be whatever is stored in the difference
variable. If 10 and 7 are passed in as arguments, the return value is 3 because the last line of the method uses the return
keyword to return the difference
variable. This is called an explicit return.
def subtract(bigger, smaller)
difference = bigger - smaller
return difference
end
subtract(10, 7)
# => 3 (return value is 3 since it is stored in the difference variable, and the last line of the method uses the return keyword)
Best Practices
Typically, we do not include an explicit return
unless it is absolutely necessary. Since ruby methods automatically return
the value of the last line, it’s common practice to use implicit returns like in the first example above.
Be Careful with puts
Inside of Your Method
In the say_goodbye
example below, notice we included the puts
command in the last line of the method instead of returning a data point. The return value is nil
because the last line of code is puts "See you later"
, and puts
is a built-in command with a return value of nil
. This is generally not a best practice, because the method doesn’t return any usable data.
def say_goodbye
puts "See you later!"
end
say_goodbye
# "See you later!" will be printed to the console
# The return value is nil because puts is on the last line of the method and the return value of the puts method is always nil
Key Point: Up until now, we’ve use the puts
and print
commands to see values printed to the console. Be careful not to confuse what you see in the console with the return value of the method – these are two different things. We use puts
and print
to see data in the console, but what we see in the console is not always the return values.
Storing a Return Value
The examples we’ve looked at so far call the method and execute the code within the method, but the return values go nowhere/can never be used in the program again. Many times, we’ll store the return value of a method in another variable, as modeled below:
def add(num1, num2)
num1 + num2
end
sum1 = add(2, 3)
sum2 = add(7, 9)
puts sum1
puts sum2
Practice
- Write a method named
get_age
. This method should declare one parameter, an Integer, representing a birth year. - When called, the method should calculate the person's approximate age. Let's not worry about birth month or day. 😉
- The method should return an Integer representing the person's age.
- Call the method several times with different arguments and store the return values in variables.
- Print a sentence that says, "You have lived ___ years of life!" with each variable interpolated into the String.
Key Points Summary
- A method is a packaged set of directions. If the method is never called, it will never run. And a method can be called many times, if needed!
- The number of arguments in a method call must match the number of parameters in the method definition.
- Method names should start with a verb and use
snake_case
. - With an implicit return, the value on the last line of the code block is the data that will be returned when a method is called.
- With an explicit return, the value after the
return
keyword is the data that will be returned when a method is called.
Self-Teach
Part of what you’ll experience at Turing is learning a technical topic on your own. Practicing this skill at Turing will get you prepared for the job where you will do this often.
Take time between now and your next session to self-teach the following section.
Warm-Up for Built-In Methods
Exploration: PART 1
In your Mod 0 Lessons Repl from the Data Types lesson, uncomment the Built In Methods Part 1 code and observe the output.
Think: How did each line of code, produce each respective line of output? Which parts make sense, and which are confusing?
Methods
A Method is a package of instructions. Once a method is defined, it can be used as many times as needed. Ruby provides many built-in methods that developers can use.
The code snippet that follows was part of the previous Exploration activity:
p 14.odd?
To describe the code snippet in English, one could say, “the odd question mark
method is being called on the Integer 14.” Since 14 is not odd, false
will be the return value. The p
command prints that return value of false
to the console.
In this particular example, the utility of the odd?
method is to determine if an Integer is odd, or not. It answers the question with a Boolean (true
or false
). The benefit of having this method built into Ruby is if a developer needs to check if a number is odd or not, they only have to type .odd?
anywhere they need to check. If they didn’t have a pre-packaged method, they’d have to write several lines of code involving logic, every time they want to check if an integer is odd. Reusability is what makes methods so powerful.
Exploration: PART 2
In the same Mod 0 Lessons Repl , comment out the code from Part 1, and uncomment the code under Part 2.
- Run the code.
- Think: What is different about this from the first set of method calls? How did each line of code, produce each respective line of output? Which parts make sense, and which are confusing?
The following code snippet demonstrates that a method can be called on a variable assigned to data:
new_string = "Hello World"
p new_string.upcase
To describe the code snippet in English, one could say, “the first line declares a variable called new_string
and the second line calls the upcase
method on the new_string
variable.” As a result, the method will return a String object where any letter character in the original String stored in new_string
will now be capitalized. The p
command prints that return value of "HELLO WORLD"
to the console. However, it’s important to note that the original data stored in new_string
is not modified permanently.
Exploration: PART 3
In the same Mod 0 Lessons Repl , comment out the code from Part 2, and uncomment the variable declarations and first method call under Part 3.
- Run the code and read the error message carefully. Work to make sense of what the problem is.
- Comment out that method call, and uncomment the next one. Run the code and read the error message carefully. Work to make sense of what the problem is.
- Repeat the previous step until you've run the code for each method call.
- Modify the existing code so that it runs without errors.
- Write down a 1-3 sentence explanation of your main takeaway from this exploration.
Key Points
- A method is a package of instructions that once defined, can be reused as many times as needed.
- A method can be called on a variable that holds data.
- Ruby provides built-in methods for each data type. Not every method will work on every type of data.