Project

General

Profile

Actions

Feature #9095

open

Allow `Symbol#to_proc` to take arguments

Added by alexeymuranov (Alexey Muranov) over 10 years ago. Updated over 10 years ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:58226]

Description

=begin
After discussing #9076, i've decided to propose this:

class Symbol
def to_proc(*args)
proc do |x|
x.public_send(self, *args)
end
end
end

p = :+.to_proc(1)

p[2] # => 3

[1, 2, 3, 4].map &:to_s.to_proc(2) #=> ["1", "10", "11", "100"]

This would allow constructing more kinds of procs without using literal blocks.
=end

Updated by Anonymous over 10 years ago

Is there any real benefit to using something like:

&:foo.to_proc(bar)

instead of:

{ |x| x.foo(bar) }

Personally I find the first form to be quite ugly and difficult to understand at first glance.

Updated by alexeymuranov (Alexey Muranov) over 10 years ago

Some prefer doing everything without variables, this is a matter of taste. I am not sure there is no better way to obtain the same proc without using literal blocks, this was the first thing that came to my mind.

Updated by Hanmac (Hans Mackowiak) over 10 years ago

i did something similar to that there:
https://bugs.ruby-lang.org/issues/9076#note-9

its more

[1, 2, 3, 4].map &:to_s.(2) #=> ["1", "10", "11", "100"]

but it can be also used as

[1, 2, 3, 4].map &:to_s.(2).size #=> [1, 2, 2, 3]

its similar in using Enumerator#lazy

Updated by alexeymuranov (Alexey Muranov) over 10 years ago

Hanmac (Hans Mackowiak) wrote:

i did something similar to that there:
https://bugs.ruby-lang.org/issues/9076#note-9

Hans, your proposal does not look good to me. IMO, it is strange to make
symbols callable and it is strange to add to the responsibilities of
Symbol to maintain some SymbolHelper, which looks to me more like a
ProcBuilder. Also, using method_missing is always a bit scary to me.

You seem to propose, instead of

[1, 10, 100].map{|x| x.to_s.length.to_f } # => [1.0, 2.0, 3.0]

to write

[1, 10, 100].map &:to_s.call.length.to_f  # => [1.0, 2.0, 3.0]

At least i would have called this method #to_symbol_helper instead of
#call.

As #method_missing will not catch calls of #to_proc, there will be
inevitably exceptions to the general rule:

[1, 2, 3].map{|i| i.method(:**).to_proc.call(2) } # => [1, 4, 9]
[1, 2, 3].map &:method.(:**).to_proc.call(2)      # => [2, 4, 8]

If i did not care about such ambiguities, i might have proposed something like this:

class ProcFromCallsBuilder < BasicObject
  ThisClass = ::Module.nesting.first

  def initialize(&block)
    @proc = block || ::Proc.new{|x| x }
  end

  def call(*a, &b)
    @proc[*a, &b]
  end

  alias [] call

  def to_proc
    @proc
  end

  def method_missing(m, *args, &block)
    ThisClass.new do |x|
      @proc[x].public_send(m, *args, &block)
    end
  end
end
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0