DEV Community

x
x

Posted on

And &, per se.

Alt Text

This blog will cover three common uses that will help clarify the purpose and application of the & operator.

  • Convert a variable into a proc
  • Shorten array enumerables
  • Safe Navigation Operator

All of these things that you can do rely on the underlying magic that Ruby provides with the & operator

Alt Text

& just works, ok?

The first use we will explore is using & to allow us to pass a block to a method and do something useful with it.

def pretty_print(&block)
puts '**' << block.call.to_s << '**'
end

pretty_print {'hello world'}
Enter fullscreen mode Exit fullscreen mode

That looks just like a regular method, only with braces, right? Not exactly. What would happen if you passed an enumerable? Suppose "('a'..'j').to_a" was our array of characters to be converted to uppercase before showing the entire array.

pretty_print { ('a'..'j').to_a.map do |letter| letter.upcase end }
Enter fullscreen mode Exit fullscreen mode

You can't do this with a method parameter. The following doesn't work since it can't convert the Array to a String implicitly.

def test_print(t)
  puts '**' << t << '**'
end

test(('a'..'j').to_a.map do |letter| letter.upcase end )
Enter fullscreen mode Exit fullscreen mode

Alt Text

Shortening enumerables

What was happening in our example above was & represented the block that we passed to it. In fact & converts what you pass to it into either a block or proc, depending on how it is used. A common use is with #map and other enumerable methods that return a new array.

If you are using #map to create a new array from an existing object, you can likely cut down on some typing. Refactoring the example above would look like this.

pretty_print { ('a'..'j').to_a.map(&:upcase) }
Enter fullscreen mode Exit fullscreen mode

Since we passed a block to &, Ruby converted this to a proc for us and the symbol :upcase refers to the method upcase which is available to the enumerable item. This could be useful with models that have a single attribute that you want an array of. For example, we could create an instance variable in one of our models.

@all_cats = Owners.all.map(&:cat)
Enter fullscreen mode Exit fullscreen mode

Nice and simple.

Alt Text

Safe Navigation Marker

Another use for & is when you want to check a value, but just want nil back if it doesn't exist instead of the dreaded NoMethodError. This allows you to presume and not worry if something doesn't exist, you are prepared to get nil back.

@owner&.cat&.name
Enter fullscreen mode Exit fullscreen mode

This is shorter an much easier to read than its counterpart

if @owner.cat
  @owner.cat.name
else
  nil
end
Enter fullscreen mode Exit fullscreen mode

It is even better than the ternary version.

@owner.cat ? @owner.cat.name : nil
Enter fullscreen mode Exit fullscreen mode

In this case, & is still converting what you pass to it as a block, but since the action occurs inside &'s block, if @owner doesn't have a cat and therefore the method for getting the cat's name doesn't exist, the block will evaluate to nil instead of throwing an error.

A powerful place to use this last example would be in a view page. You can lazily assume that parameters exist and just expect a nil output when that parameter or method doesn't exist.

Alt Text

And then?

There is also the bitwise use of & which wasn't covered in this blog. Stay tuned for more. & is an enigmatic symbol that produces interesting and useful ways to create flexible methods that wrap around other methods. Thank you for reading my blog and helping me understand these issues better with you.

Top comments (0)