Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strange issue with Contracts 0.11.0 interaction with lambdas #238

Open
alexanderdean opened this issue Jul 29, 2016 · 8 comments
Open

Strange issue with Contracts 0.11.0 interaction with lambdas #238

alexanderdean opened this issue Jul 29, 2016 · 8 comments

Comments

@alexanderdean
Copy link

First off apologies if this has been fixed in a more recent version; we use 0.11.0 at Snowplow.

In Snowplow we have a module function:

      Contract String, String => Func[String, String => String]
      def self.build_fix_filenames(region, collector_format)
        return lambda { |basename, filepath|
        ...

Now the strange thing is that when we call the function from elsewhere in the module like:

  fix_filenames_lambda = build_fix_filenames("foo", "bar")

Then the value of fix_filenames_lambda is set to the Contract - it is of class Contract - rather than set to the lambda (of class Proc).

Very odd! Removing the Contract assignment line fixes it.

@egonSchiele
Copy link
Owner

That's weird. This gist works as expected for me and prints out 2. Does it work for you?

@alexanderdean
Copy link
Author

alexanderdean commented Jul 29, 2016

Thanks for checking this @egonSchiele ! Super-weird. I took your example and ran it inside a very similar irb environment to our end-app, and it worked. I then tweaked it to make it closer to our failing code:

require "contracts"


module Foo
  module Bar

    include Contracts

    Contract String => Func[Num => Num]
    def self.test(some_arg)
      return lambda { |x|
        return x + 1
      }
    end

    def self.print_incr
      func = test("foo")
      p func[1]
    end

  end
end

Foo.print_incr

That worked too. We run in JRuby - whatever is going wrong I think is very deep in the runtime...

Thanks for looking into it! I think if you can't reproduce we will have to close this?

@alex-fedorov
Copy link
Collaborator

Hi Alexander ,

When you actually call that function, does it work or fail (regardless of
its type)?

I'm asking since I am assuming that we are wrapping returned proc into the
contract, and contract is still callable. Maybe I'm slightly off here. Need
more input.
Alexander Dean [email protected] schrieb am Fr., 29. Juli 2016 um
7:54 PM:

Thanks for checking this @egonSchiele https://github.com/egonSchiele !
Super-weird. I took your example and ran it inside a very similar irb
environment to our end-app, and it worked. I then tweaked it to make it
closer to our failing code:

require "contracts"

module Foo
module Bar

include Contracts

Contract String => Func[Num => Num]
def self.test(some_arg)
  return lambda { |x|
    return x + 1
  }
end

def self.print_incr
  func = test("foo")
  p func[1]
end

endend
Foo.print_incr

That worked too. We run in JRuby - whatever is going wrong I think is very
deep in the runtime...


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#238 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AHjleoxzdgtD0psRVcqQmEkXo3Td3GHWks5qaj5sgaJpZM4JYJeZ
.

@alexanderdean
Copy link
Author

alexanderdean commented Jul 29, 2016

Hey @alex-fedorov - that's the odd thing, the lambda is not callable. In my downstream code where I try to figure out the lambda's arity, I get this error:

NoMethodError (undefined method `arity' for #<Contract:0x675d9d69>):
    uri:classloader:/gems/sluice-0.4.0/lib/sluice/storage/s3/s3.rb:582:in `rename_file'
    uri:classloader:/gems/sluice-0.4.0/lib/sluice/storage/s3/s3.rb:494:in `block in process_files'
    org/jruby/RubyKernel.java:1290:in `loop'
    uri:classloader:/gems/sluice-0.4.0/lib/sluice/storage/s3/s3.rb:412:in `block in process_files'

@waterlink
Copy link
Collaborator

@alexanderdean As I thought. We are wrapping lambda over here: https://github.com/egonSchiele/contracts.ruby/blob/master/lib/contracts/call_with.rb#L90-L92

Therefore calling that lambda would work just fine, but not #arity. I believe we are violation LSP here, we should be implementing a proper Proc protocol/interface for this wrapper, not just one method #call.

@alexanderdean
Copy link
Author

Ah! I think I understand now. The contract on the lambda-generating function implies some kind of wrapping of the returned lambda, otherwise how can the contract of that lambda be enforced?

@waterlink
Copy link
Collaborator

Exactly!

@alexanderdean
Copy link
Author

The strange thing is that this test case is working:

require "contracts"


module Foo
  module Bar

    include Contracts

    Contract String => Func[Num => Num]
    def self.test(some_arg)
      return lambda { |x|
        return x + 1
      }
    end

    def self.print_arity
      func = test("foo")
      p func.arity
    end

  end
end

Foo.print_arity

Not sure what I am doing wrong...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants