From: Gavin Sinclair Date: 2003-10-24T16:56:35+09:00 Subject: Struggling with variable arguments to block Hi -talk, I'm having trouble dealing with a block that yields one parameter but declares two. I've pasted complete test code below. Basically, I've defined "sum" on Enumerable that sums the result of yielding each value. This is for demonstration of the problem only. When I define it like this def sum result = 0 self.each { |elt| result += yield(elt) } result end {1=>2}.sum { |k,v| v } works but gives a warning. [[1,2]].sum { |a,b| b } is fine. When I define it like this def sum result = 0 self.each { |*elt| result += yield(*elt) } result end {1=>2}.sum { |k,v| v } is fine. [[1,2]].sum { |a,b| b } gives an error. Below are the two definitions and a complete test case. In the test case, the range examples have no problems so are uncommented. Comments are given in the other cases. I would really like to avoid the warning associated with the hash in test_sum1h. Thanks for any advice, Gavin -------------------------------------------------------------------------- module Enumerable # # Yield each element and return the (strictly numerical) sum of the # results. sum1 and sum2 are different implementations. # def sum1 result = 0 self.each do |elt| result += yield(elt) end result end def sum2 result = 0 self.each do |*elt| result += yield(*elt) end result end end require 'test/unit' # # Test case: set up 3 enumerable objects, and try sum1 and sum2 on # each of them. # class TC_Sum < Test::Unit::TestCase def setup @r = (1..10) # We'll sum the squares (385) @a = [ [1,2], [3,4], [5,6] ] # We'll sum the products (44) @h = { :a => 1, :b => 2, :c => 3 } # We'll sum the values (6) end # ======== First implementation def test_sum1r puts "test_sum1r" sum = @r.sum1 { |x| x ** 2 } assert_equal(385, sum) end def test_sum1a puts "test_sum1a" sum = @a.sum1 { |x,y| x * y } # Passes. assert_equal(44, sum) end def test_sum1h puts "test_sum1h" sum = @h.sum1 { |k,v| v } # Passes, with warning: assert_equal(6, sum) # multiple values for a block end # parameter (2 for 1) # ======== Second implementation def test_sum2r puts "test_sum2r" sum = @r.sum2 { |x| x ** 2 } assert_equal(385, sum) end def test_sum2a puts "test_sum2a" sum = @a.sum2 { |x,y| x * y } # Error: no implicit conversion assert_equal(44, sum) # from nil to integer end def test_sum2h puts "test_sum2h" sum = @h.sum2 { |k,v| v } # Passes. assert_equal(6, sum) end end