2

I noticed if you type: object &, you get the object back. For example:

1.class   # => Integer
1 &.class # => Integer
'hello'.then { |x| x.equal?(x &.itself) }    # => true
[1, 2, 3] &.map(&:next)    # => [2, 3, 4]

I am unable to find a documentation for the syntax for object &.method How does this syntax work?

15 Volts
  • 1,946
  • 15
  • 37
  • Here's a link that talks about the safe navigation operator: https://stackoverflow.com/questions/45825363/what-is-the-difference-between-try-and-safe-navigation-operator-in-ruby – 15 Volts Sep 05 '19 at 21:20

2 Answers2

5

There are 2 seperate operators here:

  1. Safe navigation operator &. - It is safe navigation operator which was introduced in Ruby 2.3.0. It basically returns nil if the callee is nil instead of raising excecption undefined method called for Nil class. eg:

    a = 1
    a.next
    # => 2
    a&.next
    # => 2
    a = nil
    a.next
    # => NoMethodError (undefined method `next' for nil:NilClass)
    a&.next
    # => nil ## No exception, returns nil
    

    You can read about it more here and documentation

  2. Unary & : This operator is a little more complex. It is almost equivalent to calling #to_proc but not quite that. But for this discussion let us think like that. So, if you have a Proc, calling with & in front of it will call #to_proc on the Proc and convert it into a block

    multiply_by_2 = Proc.new { |x| x * 2 }
    # => #<Proc:0x00007fb4771cf560>
    # &multiply_by_2 almost equivalent to { |x| x * 2 } but is not correct syntax
    [1, 2].map(&multiply_by_2)
    # => [2, 4]
    # equivalent to  [1, 2].map { |x| x * 2 }
    

    But what happens if we give a symbol like :abc to & operator instead of a proc. It will try to call #to_proc on the symbol and ruby has defined Symbol#to_proc which roughly translates to something like this:

    def to_proc
      # this will return some block like { |x| x.send(:abc) }
      lambda { |x| x.send(self) }
    end
    

    So &:abc roughly translates to this block { |x| x.abc } using the below transformation

    &:abc =====> :abc.to_proc =====> { |x| x.send(:abc) } ====> { |x| x.abc }
    

    So, instead of doing [1, 2, 3].map { |x| x.next }, you could do [1, 2, 3].map(&:next) as &:next is roughly equivalent to the block { |x| x.next }.

    See unary & (which is the main source of what I have written here) for more reading.

rubyprince
  • 17,559
  • 11
  • 64
  • 104
1

It's ruby syntax, & calls to_proc on the object and passes the result as a block to the method.

An explanation from the pickaxe book, programming Ruby 1.9 and 2.0

Blocks Can Be Objects

Blocks are like anonymous methods, but there’s more to them than that. You can also convert a block into an object, store it in variables, pass it around, and then invoke its code later. Remember we said that you can think of blocks as being like an implicit parameter that’s passed to a method? Well, you can also make that parameter explicit. If the last parameter in a method definition is prefixed with an ampersand (such as &action ), Ruby looks for a code block whenever that method is called. That code block is converted to an object of class Proc and assigned to the parameter. You can then treat the parameter as any other variable. Here’s an example where we create a Proc object in one instance method and store it in an instance variable. We then invoke the proc from a second instance method.

class ProcExample

  def pass_in_block(&action)
    @stored_proc = action
  end

  def use_proc(parameter)
    @stored_proc.call(parameter)
  end
end

Use it like so

eg = ProcExample.new
eg.pass_in_block { |param| puts "The parameter is #{param}" }
eg.use_proc(99)

produces:

The parameter is 99

jamesc
  • 12,423
  • 15
  • 74
  • 113