DEV Community

Ahmad khattab
Ahmad khattab

Posted on

Opinions on Programming: Eliminating one-off variables with Object#then

Ruby is a pretty versatile language. It can be used to write OOP and Functional code at once. Ruby provides multiple meta-programming facilities as well.

One of the features of Ruby's Objects that i've come to like, is a method, namely #then.

It accepts a block, proc, or a lambda. That receives the object itself as the only argument, these "callbacks" then can modify or "tap" into the object's state. Eventually, it returns the last line from the passed lambda, which can be used to store inside a variable(which it's sibling #tap would not do)

Every Object in ruby responds to a then method. It evaluates the passed proc in the context of the caller(i.e the Object itself), then returns the last line executed inside the block. Take this class

class Person
  attr_reader :first_name, :last_name

  def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
  end

  def name
    "#{first_name} #{last_name}"
  end
end
Enter fullscreen mode Exit fullscreen mode

Given this Person class above, let's say we want to get the name of the person. We could do this,

user = Person.new "John", "Doe"

user_full_name = user.name
Enter fullscreen mode Exit fullscreen mode

Here we're storing the new Person object inside the user variable, which we're only using in a single place(to log the name to the console). With then, we can do

user_full_name = Person.new("John", "Doe").then(&:name)
Enter fullscreen mode Exit fullscreen mode

The code gotten shorter. Because we're not storing an extra variable(the user), after this code execute, the garbage collector can safely remove this Object since no reference to it exists anymore.

This really shines inside conditionals, this snippet assumes you have Rails installed(or any other database-backed table)

@buyer = if Buyer.find_by(id: 123).nil?
  SomeExternalService.api(...).then do |response|
    Buyer.create(response.body)
  end
else
  ## do something else
end
Enter fullscreen mode Exit fullscreen mode

We don't need to store the response into a variable then do Buyer.create from the response. Here is how it might look like without using then.

@buyer = if Buyer.find_by(id: 123).nil?
  response = SomeExternalService.api(...)
  Buyer.create(response.body)
else
  ## do something else
end
Enter fullscreen mode Exit fullscreen mode

Personally, i've grown to like Object#then more and more, not to mention it's sibling, Object#tap.

Thanks for staying until the end. Hope you enjoyed this, have a wonderful day, and happy coding.

Resources

Top comments (0)