Flow of Execution

Learn about the flow in which Ruby runs our code.

We'll cover the following

Feel free to skip this chapter if you understand Ruby’s program flow, defining and calling a method, returning from it, perhaps calling another method, and so on. We’ve discussed this before. Because this is a potentially confusing topic, we’ll go over it again.

Note: It’s easy for programmers to forget to explain to beginners how Ruby flows through a program and in what exact order. This is called the flow of execution, or control flow.

When we execute a Ruby file (with the ruby runtime), it reads the Ruby code and executes it line by line, from top to bottom.

Example

Let’s look at our example from before, and how the Ruby control flow goes through it, in greater depth.

We’ve added parentheses for the method call to puts to make this more obvious, even though we recommend against this in practice:

Press + to interact
def add_two(number)
number + 2
end
puts(add_two(3))

Ruby flow of control

  • Ruby starts on line 1 and finds our method definition, starting with the def keyword. It reads everything until it finds the end keyword on line 3. For now, it does nothing but define this method and keep it in memory so that it can be used later.

  • In line 4, Ruby finds that we’re using the puts word, and it sees that we’re trying to pass something to it, so this must be a method call.

  • To call a method, Ruby needs to first evaluate the values that we want to pass. So, Ruby looks at what’s between the parentheses and finds another method call, add_two(3).

  • Again, to call the method, add_two, Ruby needs to first evaluate the values that we want to pass. In this case, this is the number 3, so Ruby creates this object (an instance of the class Number). Now, it’s finally ready to call the add_two method, passing the number just created.

  • For the first time, Ruby starts to deviate from the default flow of execution, which simply goes from top to bottom. Instead, because we’re calling a method, Ruby enters the method body that we defined for the add_two method before. Control flow now jumps to line 2.

  • In this moment, since we are entering a method that has an argument, Ruby also defines a local variable number, and assigns the object that was passed, the number 3, to this variable.

  • Because we’re entering a method with an argument, Ruby also defines a local number variable and assigns the object that was passed, the number 3, to this variable.

  • Now, Ruby is ready to evaluate line 2. It finds that we’re using the + operator on the value assigned to the number variable, which is 3. To do that, Ruby first evaluates what’s on the right-hand side of the operator, which is a number in our example. Ruby creates the number (an instance of the Number class), this time with a value of 2.

  • Ruby is now ready to evaluate the operator and adds the number 2 to the number 3. This operation returns a new number (an instance of the Number class), which is 5.

  • Ruby recognizes that the method body has ended, so it returns 5 from the add_two method because this was the return value of the statement that was evaluated last.

  • The control now jumps again to line 4. Ruby is now done evaluating the method call add_two(3), which returns 5. Ruby can now finally call the puts method, passing the object 5, which Ruby then prints out.