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?
There are 2 seperate operators here:
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
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.