Skip to content

Instantly share code, notes, and snippets.

@ntamvl
Last active February 21, 2024 11:12
Show Gist options
  • Save ntamvl/9b83c31f8cc714b25c3621a5d77a99b2 to your computer and use it in GitHub Desktop.
Save ntamvl/9b83c31f8cc714b25c3621a5d77a99b2 to your computer and use it in GitHub Desktop.
How to implement a “callback” in Ruby?

How to implement a “callback” in Ruby?

This "idiomatic block" is a very core part of everyday Ruby and is covered frequently in books and tutorials. The Ruby information section provides links to useful [online] learning resources.

The idiomatic way is to use a block:

def x(z)
  yield z   # perhaps used in conjunction with #block_given?
end
x(3) {|y| y*y}  # => 9

Or perhaps converted to a Proc; here I show that the "block", converted to a Proc implicitly with &block, is just another "callable" value:

def x(z, &block)
  callback = block
  callback.call(z)
end

# look familiar?
x(4) {|y| y * y} # => 16

(Only use the above form to save the block-now-Proc for later use or in other special cases as it adds overhead and syntax noise.)

However, a lambda can be use just as easily (but this is not idiomatic):

def x(z,fn)
  fn.call(z)
end

# just use a lambda (closure)
x(5, lambda {|y| y * y}) # => 25

While the above approaches can all wrap "calling a method" as they create closures, bound Methods can also be treated as first-class callable objects:

class A
  def b(z)
    z*z
  end
end

callable = A.new.method(:b)
callable.call(6) # => 36

# and since it's just a value...
def x(z,fn)
  fn.call(z)
end
x(7, callable) # => 49

In addition, sometimes it's useful to use the #send method (in particular if a method is known by name). Here it saves an intermediate Method object that was created in the last example; Ruby is a message-passing system:

# Using A from previous
def x(z, a):
  a.__send__(:b, z)
end
x(8, A.new) # => 64

Happy coding!

Ref:

https://stackoverflow.com/questions/1677861/how-to-implement-a-callback-in-ruby

https://www.sitepoint.com/rubys-important-hook-methods/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment