100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Ruby

Defining Methods

How to define methods in Ruby using def, including implicit return values, naming conventions (?, !), visibility, and how methods differ from blocks.

Methods & BlocksBeginner9 min readJul 9, 2026
Analogies

Defining Methods

Methods are the primary unit of reusable behavior in Ruby, defined with the def keyword and closed with end. A method belongs either to a specific object (an instance method, defined inside a class or module) or to the top-level Object/Kernel when written outside any class, effectively becoming a private method available everywhere. Ruby method names conventionally use snake_case, and two punctuation suffixes carry semantic meaning by convention: a trailing ? marks a method that returns a boolean-ish value, and a trailing ! marks a method with a more "dangerous" or surprising variant of its non-bang counterpart.

🏏

Cricket analogy: A player's signature shot has a name everyone recognizes, like the Dilscoop, while an unnamed improvised swing exists but isn't formally catalogued, similar to how a named instance method belongs to a class while top-level code becomes an anonymous private Kernel method.

Implicit return, parameters, and naming conventions

Ruby methods return the value of the last evaluated expression automatically — an explicit return is only necessary for early exits from the middle of a method body. Parameters can have default values, evaluated lazily only if the caller omits the corresponding argument. Following the ?/! conventions communicates intent to future readers: a predicate method (empty?) should return a boolean-ish value and never mutate its receiver, while a bang method (shuffle!) should exist alongside a non-bang counterpart (shuffle), since the bang only carries meaning relative to that safer sibling.

🏏

Cricket analogy: A scorer doesn't need to explicitly announce the final total; the last ball bowled automatically becomes the final score, just as Ruby methods return their last evaluated expression without needing explicit return; and is_out? should just report, never physically remove the batsman, the way shuffle! needs a safe shuffle sibling.

ruby
def greeting(name, punctuation = "!")
  return "Hello, stranger#{punctuation}" if name.nil? || name.empty?

  "Hello, #{name}#{punctuation}" # implicitly returned
end

class Playlist
  def initialize(tracks = [])
    @tracks = tracks
  end

  def empty?
    @tracks.empty?
  end

  def shuffle!
    @tracks.shuffle!  # mutates this playlist's tracks in place
    self
  end
end

Method visibility

Inside a class body, methods are public by default. The private and protected keywords, used bare, switch the visibility of every subsequently defined method until the end of the class body or another visibility keyword changes it again. Private methods cannot be called with an explicit receiver (except self. for setter methods since Ruby 2.7), while protected methods can be called with an explicit receiver, but only from within another instance method of the same class or a subclass.

🏏

Cricket analogy: A team's tactics discussed openly in a press conference are public, but strategy notes passed only among players on the same team, protected, an explicit receiver but only a teammate can read it, differ from a captain's private mental notes no one else can access at all, private, no external receiver allowed.

ruby
class Account
  def initialize(balance)
    @balance = balance
  end

  def >(other)
    balance > other.balance # protected lets us access other's balance here
  end

  protected

  attr_reader :balance
end

Unlike Java or C#, where a method's return type and visibility must be declared upfront, Ruby methods have no static return-type declaration, and the last expression's value is returned automatically. This makes it easy to accidentally return the wrong value if you're not deliberate about a method's final line — a common source of subtle bugs when refactoring.

Defining a top-level method (outside any class or module) actually defines a private method on Object, making it callable from anywhere without an explicit receiver — this is convenient for small scripts but can silently pollute the method namespace of every object in a larger application if overused.

  • Methods are defined with def...end and return the value of their last evaluated expression by default.
  • return is only required for early exits; explicit returns at the end of a method are stylistically unnecessary.
  • A trailing ? conventionally marks a non-mutating boolean-returning predicate method.
  • A trailing ! conventionally marks the more dangerous/mutating sibling of a non-bang method of the same name.
  • Methods are public by default inside a class; private and protected change the visibility of everything defined after them.
  • Top-level methods (outside any class) become private methods on Object, callable anywhere without a receiver.

Practice what you learned

Was this page helpful?

Topics covered

#Ruby#RubyStudyNotes#Programming#DefiningMethods#Defining#Methods#Implicit#Return#Functions#StudyNotes#SkillVeris