I am learning rails and following this thread. I am stuck with the to_proc
method. I consider symbols only as alternatives to strings (they are like strings but cheaper in terms of memory). If there is anything else I am missing for symbols, then please tell me. Please explain in a simple way what to_proc
means and what it is used for.
Some methods take a block, and this pattern frequently appears for a block:
{|x| x.foo}
and people would like to write that in a more concise way. In order to do that they use a combination of: a symbol, the method Symbol#to_proc
, implicit class casting, and &
operator. If you put &
in front of a Proc
instance in the argument position, that will be interpreted as a block. If you combine something other than a Proc
instance with &
, then implicit class casting will try to convert that to a Proc
instance using to_proc
method defined on that object if there is any. In case of a Symbol
instance, to_proc
works in this way:
:foo.to_proc # => ->x{x.foo}
For example, suppose you write:
bar(&:foo)
The &
operator is combined with :foo
, which is not a Proc
instance, so implicit class cast applies Symbol#to_proc
to it, which gives ->x{x.foo}
. The &
now applies to this and is interpreted as a block, which gives:
bar{|x| x.foo}
&proc
gives a block, &x
results in x becoming proc then whole thing also gives a block. I also understand that Symbol has to_proc method. However the part i dont understand and i feel this answer lacks, is how symbol and methods are connected. i mean it's not like all methods are also available by the symbol names –
Kutaisi 1.to_s
and 1.send(:to_s)
. So really (1..10).each(&:to_s)
is equivalent to (1..10).each { |x| x.send(:to_s) }
. The symbol is passed as an argument to the send()
method. Look at this link. –
Proceeds The easiest way to explain this is with some examples.
(1..3).collect(&:to_s) #=> ["1", "2", "3"]
Is the same as:
(1..3).collect {|num| num.to_s} #=> ["1", "2", "3"]
and
[1,2,3].collect(&:succ) #=> [2, 3, 4]
Is the same as:
[1,2,3].collect {|num| num.succ} #=> [2, 3, 4]
to_proc returns a Proc object which responds to the given method by symbol. So in the third case, the array [1,2,3] calls its collect method and. succ is method defined by class Integer. So this parameter is a short hand way of saying collect each element in the array and return its successor and from that create a new array which results in [2,3,4]. The symbol :succ is being converted to a Proc object so it call the Array's succ method.
For me the clearest explanation is seeing a simple implementation of it. Here's what it might look like if I were reimplementing Symbol#to_proc:
class Symbol # reopen Symbol class to reimplement to_proc method
def to_proc
->(object) { object.send(self) }
end
end
my_lambda = :to_s.to_proc
puts my_lambda.(1) # prints '1'; .() does the same thing as .call()
puts my_lambda.(1).class # prints 'String'
puts [4,5,6].map(&:to_s) # prints "4\n5\n6\n"
puts [4,5,6].map(&:to_s).first.class # prints 'String'
Symbol#to_proc
does not. –
Aposiopesis Proc.new { |object| object.send(self) }
? –
Reeding irb
, the monkey-patched version of :foo.to_proc
gave me this: #<Proc:0x00007f8e132627a0@(irb):19>
, while the original gave me this: #<Proc:0x00007ffcb31d5fd0(&:foo)>
. I tried running the patch from a file called test.rb
and got this: #<Proc:[email protected]:35>
. Apparently, in the patch version, self
refers to the main environment rather than the symbol, so there must be more to it. –
Aposiopesis public; def foo; "Hi, I'm foo."; end
, and this call: p [''].map(&:foo)
. Works with the original and the monkey-patch. –
Aposiopesis For anybody still a bit stumped, running the following code might make things a little clearer:
class Symbol
def to_proc
proc do |obj|
puts "Symbol proc: #{obj}.send(:#{self})"
obj.send(self)
end
end
end
class Array
def map(&block)
copy = self.class.new
self.each do |index|
puts "Array.map: copy << block.call(#{index})"
copy << block.call(index)
end
copy
end
end
remapped_array = [0, 1, 2].map &:to_s
puts "remapped array: #{remapped_array.inspect}"
These are not the actual implementations of Symbol.to_proc
or Array.map
, they are just simplified versions which I'm using to demonstrate how map &:to_s
and similar calls work.
© 2022 - 2024 — McMap. All rights reserved.
to_proc
can be used in practice. However I found these simple documentation links a better answer for "what is it", including "what is aProc
", which is whatto_proc
returns. apidock.com/rails/Symbol/to_proc ruby-doc.org/core-2.2.0/Proc.html – Roundhead