Continued looking at properties in D - interfaces and constraints

mikey via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Wed Oct 12 13:40:57 PDT 2016


On Wednesday, 12 October 2016 at 08:36:43 UTC, Jonathan M Davis 
wrote:
> That's exactly what it does. Having no contract is considered 
> to be equivalent to having an empty contract. So, because an 
> empty contract will never fail, not having an in contract in 
> the base class (or interface) function is equivalent to not 
> having any in contracts anywhere in the inheritance chain, 
> which is pretty annoying. The ||ing and &&ing done with in and 
> out contracts and inheritance is critical to having contracts 
> work correctly with inheritance. And in contracts work properly 
> when each level declares one, but it probably would be better 
> if having an in contract were illegal if the base class didn't 
> have one, since then you'd at least avoid accidentally having 
> an in contract that's pointless. out contracts shouldn't have 
> any of these problems though, since they're &&ed, and &&ing 
> with true doesn't change anything. Missing in contracts 
> definitely is an easy way to introduce bugs into your contracts 
> though.
>
> - Jonathan M Davis


OK I'm somewhat struggling with this concept.

As I see it the "in" contract can only place a limit on what 
values are valid to come in to the method. I could maybe see some 
questionable argument to make any contract for values coming into 
the method a subset of the previous valid values, but what you 
are describing is the opposite: that each contract has to be a 
superset of all the previous contracts for valid values!

This seems limiting at best, but worse completely at odds with 
the concept of inheritance building from the most general to the 
most specific case.

Say I have worker:

     import std.exception;

     class Worker {
     private:
         uint _wage = 10_000;

     public:
         @property uint wage() { return _wage; }
         @property void wage(uint wage)
         in {
             enforce(wage >= 10_000 && wage <= 1_000_000_000);
         } body {
             _wage = wage;
         }
     }

     class WageSlave : Worker {
     private:
         uint _wage = 10_000;

     public:
         override @property uint wage() { return _wage; }
         override @property void wage(uint wage)
         in {
             enforce(wage >= 10_000 && wage <= 40_000);
         } body {
             _wage = wage;
         }
     }

     class CEO : Worker {
     private:
         uint _wage = 1_000_000;

     public:
         override @property uint wage() { return _wage; }
         override @property void wage(uint wage)
         in {
             enforce(wage >= 1_000_000 && wage <= 1_000_000_000);
         } body {
             _wage = wage;
         }
     }

     void main() {
         auto worker = new Worker;
         assertThrown( worker.wage = 9_999 );
         assertThrown( worker.wage = 1_000_000_001 );
         assertNotThrown( worker.wage = 10_000 );
         assertNotThrown( worker.wage = 1_000_000_000 );

         auto slave = new WageSlave;
         assertThrown( slave.wage = 9_999 );
         assertThrown( slave.wage = 1_000_000_001 );
         assertNotThrown( slave.wage = 10_000 );
         assertNotThrown( slave.wage = 1_000_000_000 ); // BAD - 
no throw

         auto ceo = new CEO;
         assertThrown( ceo.wage = 9_999 );
         assertThrown( ceo.wage = 1_000_000_001 );
         assertNotThrown( ceo.wage = 10_000 ); // BAD - no throw
         assertNotThrown( ceo.wage = 1_000_000_000 );
     }




More information about the Digitalmars-d-learn mailing list