Suggested Change to Contract Syntax

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Thu Mar 10 20:35:06 PST 2016


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


More information about the Digitalmars-d mailing list