contracts.ruby icon indicating copy to clipboard operation
contracts.ruby copied to clipboard

Allow contractual reference to yet to be defined modules

Open nixpulvis opened this issue 9 years ago • 6 comments

The following results in an error, despite being completely valid code without the contracts.

class A
  Contract None => B
  def foo
    B.new
  end
end

class B
  Contract None => A
  def foo
    A.new
  end
end

puts A.new.foo
puts B.new.foo

Sure I could do something like

class A
end
class B
end

at the top of the file, but this is not a good solution.

Honestly, the more I think about it, the more I think contracts belong inside the method. This will make scope issues easier (I think) because contracts are executed within the context of the method anyway. This also could allow ruby to handle issues like #104 naturally.

nixpulvis avatar Mar 11 '15 19:03 nixpulvis

This is a Ruby issue...you can't use a symbol that isn't defined yet. The following non-contracts code would fail too:

class A
  B.new
  def foo
    B.new
  end
end

class B
  def foo
    A.new
  end
end

I'm wondering if the Rec idea from issue #101 could be used here too. I don't want to include contracts inside a method because that will break multi-dispatch.

egonSchiele avatar Mar 11 '15 19:03 egonSchiele

Right, I forgot that this gem provides multi-dispatch for a moment. That throws a wrench in the classical contract system.

The problem with using Rec for these cases, is that Rec requires you to write the contracts differently, using a string or symbol or something. In the case of recursive datatypes it's unavoidable, but here it should be avoidable. Normally I'd say it's trivial to simply use the namespace of the method, but I haven't given multi-dispatch in this context enough thought.

It would be a shame for people to need to think about the load order of their modules in order to write the correct contracts.

nixpulvis avatar Mar 11 '15 19:03 nixpulvis

Closing this in favor of #157

waterlink avatar Sep 04 '15 21:09 waterlink

I'm sorry maybe I'm being slow but how does #157 solve this?

nixpulvis avatar Sep 04 '15 21:09 nixpulvis

#157 will add additional syntax that uses isolated namespace and can be evaluated lazily, i.e.:

Contract { [c.Num => MyApp::YetToBeDefined] }

# ...
class MyApp::YetToBeDefined
  # ...
end

waterlink avatar Sep 04 '15 22:09 waterlink

On the other hand, I think you are right. This still should be opened. And this solution with isolated namespace solves more this issue rather than #157

waterlink avatar Sep 04 '15 22:09 waterlink