unexpected ArgumentError in curried Proc #1523

Closed
phluid61 opened this Issue Feb 22, 2014 · 4 comments

Projects

None yet

2 participants

@phluid61
Contributor

This Travis run shows an unexpected ArgumentError in Proc#call after sequential calls to #curry and #call

Effective code is:

l = lambda{|a,b,c| a+b+c }
l1 = l.curry.call(1)
l2 = l1.curry.call(2)
l2.curry.call(3) #=> 6
l1.curry.call(2,3) #=> ArgumentError

Ruby version is: jruby 1.7.9 (1.9.3p392) 2014-02-10 87b108a on Java HotSpot(TM) 64-Bit Server VM 1.7.0_51-b13 [linux-amd64]

@headius
Member
headius commented Feb 22, 2014

Confirmed. Same error in Rubinius, with whom we share a pure-Ruby implementation of curry: https://github.com/jruby/jruby/blob/master/core/src/main/ruby/jruby/kernel/proc.rb

It would appear something's not quite right there.

@headius
Member
headius commented Feb 22, 2014

It appears there's some interaction between the multiple curries. If I remove the curries unrelated to the error path, it works fine.

@headius
Member
headius commented Feb 22, 2014

Here's a patch that fixes the problem, and this may be sufficient for now. I believe the primary change is isolating arity and args from each level of currying by funneling them through this other method.

diff --git a/core/src/main/ruby/jruby/kernel19/proc.rb b/core/src/main/ruby/jruby/kernel19/proc.rb
index 617d68b..9a3c38d 100644
--- a/core/src/main/ruby/jruby/kernel19/proc.rb
+++ b/core/src/main/ruby/jruby/kernel19/proc.rb
@@ -16,19 +16,7 @@ class Proc
       end
     end

-    args = []
-
-    my_self = self
-    m = lambda? ? :lambda : :proc
-    f = __send__(m) {|*x|
-      call_args = args + x
-      if call_args.length >= my_self.arity
-        my_self[*call_args]
-      else
-        args = call_args
-        f
-      end
-    }
+    f = Proc.__make_curry_proc__(self, [], arity)

     f.singleton_class.send(:define_method, :binding) {
       raise ArgumentError, "cannot create binding from f proc"
@@ -44,4 +32,21 @@ class Proc

     f
   end
+
+  def self.__make_curry_proc__(proc, passed, arity)
+    is_lambda = proc.lambda?
+    passed.freeze
+
+    __send__((is_lambda ? :lambda : :proc)) do |*argv, &passed_proc|
+      my_passed = passed + argv
+      if my_passed.length < arity
+        if !passed_proc.nil?
+          warn "#{caller[0]}: given block not used"
+        end
+        __make_curry_proc__(proc, my_passed, arity)
+      else
+        proc.call(*my_passed)
+      end
+    end
+  end
 end

This logic is ported from Ruby 2.1.

I will probably go ahead with this fix and then look at eliminating the existing singleton logic (unrelated to this bug).

@headius headius referenced this issue in rubinius/rubinius Feb 22, 2014
Closed

unexpected ArgumentError in curried Proc #2951

@headius headius added this to the JRuby 1.7.12 milestone Feb 22, 2014
@headius
Member
headius commented Feb 22, 2014

I've pushed my fix to the post-11 branch, which I'll merge to jruby-1_7 and master once 1.7.11 has been released.

@headius headius closed this in 7270345 Feb 26, 2014
@tak1n tak1n referenced this issue in rubinius/rubinius May 23, 2015
Merged

fix Proc#curry #3406

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment