You're Doing In-Conditions Wrong

Steven Schveighoffer schveiguy at gmail.com
Tue Jul 14 16:09:59 UTC 2020


On 7/14/20 11:37 AM, FeepingCreature wrote:
> On Tuesday, 14 July 2020 at 13:37:58 UTC, Steven Schveighoffer wrote:
>> But I somewhat disagree. Yes, you can write bad contracts, but that is 
>> not on the compiler, and can't really be checked by the compiler. The 
>> compiler enforces the rule by ignoring what the derived class does if 
>> the parent class passes. It doesn't enforce the logic of your contract 
>> fits the rule.
>>
> 
> It can be checked by the compiler just fine at runtime. IMO, this is 
> what unittests are for.

But the derived contracts are intended to be used only if the base 
contract fails. It's not entirely inappropriate or unheard of to write 
such a contract with that in mind.

What you are asking for is to require the derived contracts to implement 
the base contract's conditions that allow the same inputs.

Let's look at an example similar to what you wrote:

class A
{
     void foo(int i) in (i == 3) {} // accept only 3
}

class B : A
{
     override void foo(int i) in (i == 2) {} // accept 3 OR 2.
}

If the intention of B is to accept 3 or 2, then it is written correctly. 
Your proposal wants to say that B should only be valid if written like:

class B : A
{
     override void foo(int i) in (i == 2 || i == 3) {}
}

This would be like getting rid of else if:

if(i == 2) { }
/*else*/ if(i != 2 && i == 3) {}

> 
>> However, it is tedious that one has to repeat all the super's contract 
>> if your additive contract is unrelated.
>>
>> One possibility is to consider a way to say "everything super said and 
>> ..."
>>
>> maybe like:
>>
>> void foo(int i) in(super.in) in(i > 5) {}
>>
> 
> That would also be nice, but it would be nice regardless of my proposal.

Actually, I take this back. I don't think we need this (obviously, if we 
get to this contract, super.in has failed, there's no reason to test it 
again). What is needed is testing part of the parent contract, which can 
only be done via encapsulation of the test into a function that can be 
called.

I still think the biggest problem with contracts is the no-contract 
handling for derived types. It's just too easy to erase the base 
contract by accident.

-Steve


More information about the Digitalmars-d mailing list