Swift style conditionals in Ruby

The Swift programming language has a neat feature that guarantees the presence of optional values in conditionals.

// possibleName is an optional variable, it maybe hold a name, or it may be nil
if  (name = possibleName} {
  // name is guaranteed to not be nil
  // name is also declared as a constant, so it will always be available.
  println(name)
}

This method of exacting the optional value into a local constant for use inside the conditional state is a first class construct.

In Ruby you can use these same constructs to a similar effect, although there are pitfalls to using this pattern. You can assign to variables in the conditional check, however, unlike Swift, in Ruby you can only declare throwaway variables, which opens up the possibility of the value mutating later in the code. The new name variable also exists outside the scope of the conditional, polluting the namespace.

In Ruby

if name = possibleName
  # assuming name is not reassigned, it will be a value
  puts name
  # However, as name is a variable, we can reassign it
  name = 123
  puts name
end
# name is still available outside
puts name

Using Tap

A Ruby solution to this would wrap the conditional in a block, that would provide the variable to only the block. Object#tap does exactly this, but unfortunately, this approach does not protect us from the possibleName being nil, so we'd still need to check that possibleName has a value.

possibleName.tap do |name|
  puts name if name != nil
end
puts name # NameError

Write your own

Because Ruby is the awesome language that it is, we can extend the behaviour of the Object class. Here, I've defined an Object#plug method, like Object#tap it yields itself to the supplied block, unlike Object#tap, it won't yield if 'self' is nil. In hindsight, a better method name could have been Object#tap!

class Object
  def plug
    yield self if block_given? && self != nil
  end
end

"Some string".plug do |name|
puts name
end
# => Some string

nil.plug do |name|
puts name
end
# this does nothing

This gets us pretty close to the swift unboxed value example. The harder part is making this temporary variable immutable, and that's a problem for another day.