[BUG] Yielding from a method fails to call to_proc on a block_pass
Reported by hoopy | February 25th, 2008 @ 04:11 PM | in 1.0 preview
class Symbol
# Turns the symbol into a simple proc, which is especially useful for enumerations.
def to_proc
Proc.new { |*args| args.shift.__send__(self, *args) }
end
end
(1..100).inject(&:+)
# 1.8 => 5050
# 1.9 => 5050
# rbx => No method 'call' on instance of Symbol. (NoMethodError)
Comments and changes to this ticket
-

Charles L February 26th, 2008 @ 03:41 AM
Rubinius isn't coercing the arg to be a block. If you call &(:+.to_proc) explicitly, then that problem goes away. I expect this is a compiler change, to perhaps always call to_proc.
Note that this isn't the usual Symbol#to_proc, and it does turn up an interesting difference in rubinius evaluation order:
on rubinius:
>> a = [1, 2] => [1, 2] ?> a.shift.send(:+, *a) ArgumentError: wrong number of arguments (got 2, required 1) from Object#irb_binding {} at (irb):39Whereas that returns 3 on ruby 1.8, 1.9, and jruby.
Its perhaps not strictly a bug, but i think its preferable (and expected) that the method receiver is evaluated before its arguments.
-
Wilson Bilkovich February 28th, 2008 @ 10:42 AM
- → Title changed from yield/block problem? to [BUG] Yielding from a method fails to call to_proc on a block_pass
- → State changed from new to open
-
Ryan Davis February 29th, 2008 @ 06:55 PM
- → Assigned user changed from to Wilson Bilkovich
-
Wilson Bilkovich March 8th, 2008 @ 07:39 PM
- → State changed from open to resolved
This has been fixed in HEAD. Thanks for finding this.
The version of Symbol#to_proc provided by ActiveSupport is, however, broken on rbx because it expects left-to-right evaluation order.
I have checked in a version of Symbol#to_proc in core that avoids this issue. The eval order problem will be handled in a separate ticket.
-
Nikos D. April 15th, 2008 @ 02:34 PM
Okay, I think I found something really interesting. First of all my apologies for the lengthy code/examples. Now let's cut to the point...
This is the old Symbol#to_proc:
class Symbol # Turns the symbol into a simple proc, which is especially useful for enumerations. def to_proc Proc.new { |*args| args.shift.__send__(self, *args) } end endAnd here are some results:
irb(main):023:0> (1..100).map(&:to_s)
ArgumentError: base must be between 2 and 36
irb(main):020:0> (1..100).inject(&:+)
ArgumentError: wrong number of arguments (got 2, required 1)
irb(main):022:0> [(1..10).to_a, (1..10).to_a].map(&:to_s)
ArgumentError: wrong number of arguments (got 1, required 0)
irb(main):019:0> (1..100).inject(&:to_s)
ArgumentError: wrong number of arguments (got 2, required 1)
Now, here is the updated (current version):
class Symbol def to_proc Proc.new { |rec, *args| rec.__send__(self, *args) } end endand these are the results:
irb(main):029:0> (1..100).map(&:to_s)
=> ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", (....)
irb(main):030:0> (1..100).inject(&:+)
=> 5050
irb(main):032:0> [(1..10).to_a, (1..10).to_a].map(&:to_s)
ArgumentError: wrong number of arguments (got 9, required 1)
irb(main):031:0> (1..100).inject(&:to_s)
ArgumentError: wrong number of arguments (got 1, required 0)
Better but still not good enough.
Now, here's an updated version:
class Symbol def to_proc Proc.new { |*args| obj = args.shift args.empty? ? obj.__send__(self) : obj.__send__(self, *args) } end endand:
irb(main):041:0> (1..100).map(&:to_s)
=> ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", (.....)
irb(main):042:0> (1..100).inject(&:+)
=> 5050
irb(main):044:0> [(1..10).to_a, (1..10).to_a].map(&:to_s)
=> ["12345678910", "12345678910"]
BUT:
irb(main):012:0> (1..100).inject(&:to_s)
ArgumentError: wrong number of arguments (got 1, required 0)
and that's because the #inject yields two parameters in the block. So it makes sense that this one fails (and I can't figure an elegant way to make it work)
But the question is, why doesn't the old version work in rubinius as it works in ruby1.8 and 1.9 and JRuby and so forth? Because for some reason the * (splat) operator does not behave the same. I have already post a ticket for this which is #495 . If you want go check it out. I will upload a patch for this (the #to_proc) in a minute.
P.S.: Should I create a new ticket or post it here???
-
-
Please Login or create a free account to add a new comment.
You can update this ticket by sending an email to from your email client. (help)
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
