Reason #172 • June 21st, 2026

Print debugging with Kernel#p

The go-to method for print debugging tends to be puts, which prints a human-readable representation of the objects it receives. However, for debugging purposes, it is often more useful to use Kernel#p, which prints the result of calling #inspect on the objects it receives.

Consider the following:

Ruby
array = [1, 2, [3, 4], 5]

puts array
# Output:
# 1
# 2
# 3
# 4
# 5

p array
# Output:
# [1, 2, [3, 4], 5]
    

As you can see, puts goes out of its way to create human-readable output, which includes recursively iterating into nested arrays and printing each element on a new line, hiding the fact that 3 and 4 are actually part of a nested array.

On the other hand, p gives us a more accurate representation of the object.

Another difference is that puts returns nil, while p returns the object it printed, which can be handy when we want to sprinkle some debug prints of method return values or assignments:

Ruby
require "net/http"
require "json"

def get_todos
  todos_body = Net::HTTP.get(URI("https://jsonplaceholder.typicode.com/todos"))
  p JSON.parse(todos_body)
end

completed = p get_todos.select { |todo| todo["completed"] }
# Output:
# [<all the todos>]
# [<completed todos>]
    

p can also accept multiple arguments. Each object will be printed on its own line, and the return value will be an array of the objects:

Ruby
p "Hello", [1, 2, 3], { a: 1 }
# Output:
# "Hello"
# [1, 2, 3]
# {:a=>1}
# => ["Hello", [1, 2, 3], {a: 1}]
    

Though my go-to approach to debugging tends to be binding.irb or the debug gem, for cases when printing makes sense, p is a great choice.

History

Kernel#p has been part of Ruby since its inception. However, the original method only accepted a single argument and returned nil, just like puts.

Ruby 1.2, released in 1998, added support for multiple arguments.

Ruby 1.9.0, released in 2007, finally implemented the return value behaviour.

Ruby 2.0, released in 2013, made p write its output uninterruptibly, avoiding issues with e.g. output interleaving in multi-threaded programs.

Reason #173 ?