1

An answer to a question I posed yesterday on here was the following piece of Ruby code:

def overlap?(r1,r2)
  r1.include?(r2.begin) || r2.include?(r1.begin)
end

def any_overlap?(ranges)
  ranges.sort_by(&:begin).each_cons(2).any? do |r1,r2|
  overlap?(r1, r2)
  end
end

I get each_cons, but what's the strange &:begin notation? Save me from syntax hell!

Thanks!

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
mbm
  • 1,902
  • 2
  • 19
  • 28
  • This more or less a duplicate of [Understanding `[ClassOne, ClassTwo].each(&:my_method)`](http://StackOverflow.Com/q/99318/), [What does `map(&:name)` mean in Ruby?](http://StackOverflow.Com/q/1217088/), [What exactly is is this in ruby: `&:capitalize`](http://StackOverflow.Com/q/1792683/), [Ruby/Ruby on Rails ampersand colon shortcut](http://StackOverflow.Com/q/1961030/), [Ruby : `&:symbol` syntax](http://StackOverflow.Com/q/2096975/), [What is this `&:last` Ruby Construct Called?](http://StackOverflow.Com/q/2211751/), ... – Jörg W Mittag Dec 22 '10 at 22:19
  • ... [What do you call the `&:` operator in Ruby?](http://StackOverflow.Com/q/2259775/), [What does `map(&:name)` do in this Ruby code?](http://StackOverflow.Com/q/2388337/), [What are `:+` and `&+` in ruby?](http://StackOverflow.Com/q/2697024/) and [`&:views_count` in `Post.published.collect(&:views_count)`](http://StackOverflow.Com/q/3888044/). – Jörg W Mittag Dec 22 '10 at 22:20

3 Answers3

7

When you prefix the last argument of a call with & you are making clear that you are sending a block and not a normal argument. Ok, in method(&:something), :something is a symbol, not a proc, so Ruby automatically calls the method to_proc to get a real block. And Rails guys (and now also vanilla Ruby) cleverly defined it as:

class Symbol
  def to_proc
    proc { |obj, *args| obj.send(self, *args) }
  end
end

That's why you can do:

>> [1, 2, 3].map(&:to_s) # instead of [1, 2, 3].map { |n| n.to_s }
=> ["1", "2", "3"]

[edit] Note: when you realize that this construction is no syntatic sugar but generic infrastructure that Ruby provides, nothing stops you from implementing your own to_proc for other classes. Never felt limited because &:method allowed no arguments?

class Array
  def to_proc
    proc { |obj, *args| obj.send(*(self + args)) }
  end
end

>> ["1", "F", "FF"].map(&[:to_i, 16])
=> [1, 15, 255]
tokland
  • 66,169
  • 13
  • 144
  • 170
2

my_method(&some_value) means to invoke my_method, passing some_value in the special argument slot, the proc-slot, usually reserved for passing do-notation blocks.

my_block = lambda { puts "hello" }
(1..3).each(&my_block)

Any object which is a Proc or which responds to to_proc is permitted to be passed in the proc-slot. If you pass in an object which is not a Proc but which responds to to_proc, then Ruby will call to_proc on the object for you and pass the result into the method.

The implementation of Symbol#to_proc is to return a proc which, when passed an argument, sends that argument the message that is the symbol itself. For example, :hello.to_proc.call(my_obj) will end up doing my_obj.send :hello.

So my_array.each(&:hello) passes :hello to each in the proc-slot (where a block would normally passed, if you used the do-notation to make a block). :hello.to_proc.call(my_array[0]) ends up being my_array[0].send :hello, and the same for all subsequent indexes of my_array.

yfeldblum
  • 65,165
  • 12
  • 129
  • 169
1

it equals:

ranges.sort_by{|r| r.begin}
Jimmy Huang
  • 4,252
  • 2
  • 22
  • 22