Reason #158 • June 7th, 2026

Dynamic method dispatch with Kernel#send

One of the fundamental ideas in Ruby is that our programs are made up of objects that send and receive messages from each other. Thus the deeper mental model of what we do when we execute object.some_method is that we are "sending the some_method message to object".

One way this becomes explicit is with Kernel#send, available on all objects, which allows us to send a message by passing a name and arguments determined at runtime:

Ruby
class MyClass
  def greeting(name)
    "Hello, #{name}!"
  end
end

instance = MyClass.new
instance.send(:greeting, "Alice")
# "Hello, Alice!"
    

Let's make a version of the CLI tool we created yesterday while discussing ARGV that dispatches to a module method rather than a lambda:

Ruby
puts "Usage: cli.rb <command> [args...]" and exit if ARGV.empty?

module CLI
  def self.greet(name)
    puts "Hello, #{name}!"
  end

  def self.add(x, y)
    puts x.to_i + y.to_i
  end
end

command = ARGV.shift.to_sym

abort "ERROR: Unknown command - #{command}" unless CLI.singleton_methods.include?(command)

CLI.send(command, *ARGV)
    

So effortless!

Note how we use Object#singleton_methods to verify that the command is defined on the module before sending it.

Of course there is nothing stopping us from using a class instead of a module, but following the principle of functions are simpler than classes and noting that we don't need to maintain any state, a module is a more natural fit here.

History

Kernel#send has been around since Ruby's inception.

The idea of objects sending messages to each other comes from Smalltalk, though Smalltalk's equivalent of send is called perform.

Another language which leans heavily into the message sending metaphor is Objective-C, where all method calls are actually message sends, and the equivalent of send is called objc_msgSend.