On Friday, 11 March 2016 at 04:17:51 UTC, jmh530 wrote:
On Friday, 11 March 2016 at 01:45:36 UTC, Jonathan M Davis wrote:

Sure, but if you're not using in/out contracts with a class, you're not going to see how they interact with inheritance. To mimic what they do, you'd have to duplicate the base class contracts in the derived class and make sure that you ||ed the in contracts correctly and &&ed the out contracts correctly, which isn't very maintainable.

- Jonathan M Davis

If I'm understanding you correctly, you could still get the same behavior with something like below (though it isn't exactly right since Base.foo's in block would technically have a funky rule applied to it).

Yeah, you can do something like that and get it to work, but it gets increasingly tricky, the more complicated the contracts are, and it's pretty easy to screw it up. Certainly, it's far cleaner and less error-prone to have it built into the language like we do.

After playing around with your example, I'm finding in/out blocks on derived classes to be tricky. I think I'm going to try to avoid putting myself in a situation where I would screw something up.

Yeah. Having complicated contracts is probably a bad idea in general, but it gets far worse when inheritance is involved. And you can give yourself some weird problems even with the built-in help that D gives you. For instance, in my example, the derived class' in contract was a looser version of the base class' in contract, which is usually what you'd be looking to do, but the way it works is that the bass class' in contract and the derived class' in contract are ||ed. So, technically, you could make it so that the two contracts are completely distinct or so that the derived class' in contract is tighter, but what you ultimately end up with is the two in contracts ||ed, whereas what most folks will probably expect at a glance is that the derived class' contract will be met. So, doing something like

base class: assert(i < 50);
derived class: assert(i < 10);

or

bass class: assert(i < 50);
derived class: assert(i > 50);

will quickly make it so that you could have a derived class function which expects the derived class' in contract to be pass when it doesn't, because what's tested is the ||ing or the contracts not just the derived class contract.

So, ultimately, you still have to be familiar with how the in and out contracts are supposed to work with inheritance to avoid shooting yourself in the foot, but having it built in makes it so that it's harder to screw it up. It just doesn't fix the whole problem for you.

Regardless, I'd be _very_ careful with contracts and inheritance, and having complicated contracts with inheritance seems a bit suicidal.

- Jonathan M Davis

Reply via email to