www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - class invariants and property declarations

reply Michael Engelhardt <me mindcrime-ilab.de> writes:
Hi,
I just have started diving in D. Exploring the contract feature I
stumbled upon the fact that a class invariant does not apply to properties:

import std.stdio;

void main(string[] args) {
    Time t = new Time();
    t.hours = 24; // works; why?
    writeln("t.hours is ", t.hours);
    t.add(1); // triggers an assertion failure as expected
    writeln("t.hours is ", t.hours);
}

class Time {
    invariant() {
        assert( 0 <= hours && hours < 13);
    }
     property int hours;

    public void add(int hours) {
        this.hours += hours;
    }
}

compiled using Digital Mars DMD (2.051 on Ubuntu 10.10) is given the
following result:

t.hours is 24
core.exception.AssertError invarprop(13): Assertion failure
----------------
./InVariantProperty() [0x8057ade]
./InVariantProperty() [0x804f7e6]
./InVariantProperty() [0x804cba3]
./InVariantProperty() [0x8049856]
./InVariantProperty() [0x804fa86]
./InVariantProperty() [0x8049869]
./InVariantProperty() [0x8049813]
./InVariantProperty() [0x804f9f2]
./InVariantProperty() [0x804f94c]
./InVariantProperty() [0x804fa36]
./InVariantProperty() [0x804f94c]
./InVariantProperty() [0x804f8f4]
/lib/libc.so.6(__libc_start_main+0xe7) [0xa5cce7]
./InVariantProperty() [0x8049721]

Should not a class invariant apply to properties, too?

Kind regards

Michael
Feb 16 2011
next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 16.02.2011 11:03, Michael Engelhardt wrote:
 Hi,
 I just have started diving in D. Exploring the contract feature I
 stumbled upon the fact that a class invariant does not apply to properties:

Invariant gets called on every public method call (at begin & end if I'm not mistaken). Now to properties, this is actually shouldn't be allowed: property int hours; property is a annotation applied to functions (getter/setter), to allow calling it with omitted () and a natural assign syntax like this: class Time { private: int _hours; public: //... property int hours() { return _hours; } property void hours(int newHours) { _hours = newHours; } } auto t = new Time(); t.hours = 5; // calls void hours(5) assert(t.hours == 5); //calls int hours() Now given that setter and getter are public methods they'd got the invariant called.
 import std.stdio;

 void main(string[] args) {
      Time t = new Time();
      t.hours = 24; // works; why?
      writeln("t.hours is ", t.hours);
      t.add(1); // triggers an assertion failure as expected
      writeln("t.hours is ", t.hours);
 }

 class Time {
      invariant() {
          assert( 0<= hours&&  hours<  13);
      }
       property int hours;

      public void add(int hours) {
          this.hours += hours;
      }
 }

 compiled using Digital Mars DMD (2.051 on Ubuntu 10.10) is given the
 following result:

 t.hours is 24
 core.exception.AssertError invarprop(13): Assertion failure
 ----------------
 ./InVariantProperty() [0x8057ade]
 ./InVariantProperty() [0x804f7e6]
 ./InVariantProperty() [0x804cba3]
 ./InVariantProperty() [0x8049856]
 ./InVariantProperty() [0x804fa86]
 ./InVariantProperty() [0x8049869]
 ./InVariantProperty() [0x8049813]
 ./InVariantProperty() [0x804f9f2]
 ./InVariantProperty() [0x804f94c]
 ./InVariantProperty() [0x804fa36]
 ./InVariantProperty() [0x804f94c]
 ./InVariantProperty() [0x804f8f4]
 /lib/libc.so.6(__libc_start_main+0xe7) [0xa5cce7]
 ./InVariantProperty() [0x8049721]

 Should not a class invariant apply to properties, too?

 Kind regards

 Michael

-- Dmitry Olshansky
Feb 16 2011
next sibling parent reply Jesse Phillips <jessekphillips+D gmail.com> writes:
Dmitry Olshansky Wrote:

 Now to properties, this is actually shouldn't be allowed:
 
    property int hours;
 
  property is a annotation applied to functions (getter/setter), to allow
calling it with omitted () and a natural assign syntax like this:

Why shouldn't it be allowed? While it provides no benefit it does document that it is a property.
Feb 16 2011
next sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 16.02.2011 20:47, Jesse Phillips wrote:
 Dmitry Olshansky Wrote:

 Now to properties, this is actually shouldn't be allowed:

     property int hours;

  property is a annotation applied to functions (getter/setter), to allow
calling it with omitted () and a natural assign syntax like this:


the property per see it's data member, you can even take it's address. To me such 'features' that silently do nothing should be an error. As to document anything then the comment does it and without the phantom semantic load. -- Dmitry Olshansky
Feb 16 2011
prev sibling parent Jesse Phillips <jessekphillips+D gmail.com> writes:
Jonathan M Davis Wrote:

 Except that  property is for _functions_. You mark a function with  property
so 
 that it _acts_ like a variable.  property on a variable is _meaningless_. It 
 would be like marking a variable nothrow. It makes no sense. Neither should be 
 legal. The fact that a member variable is public makes it a property.
 property 
 on a member variable makes no sense.
 
 - Jonathan M Davis

class Foo { property { int min; int hour() { return _hour;} ... } } I agree that useless markings should usually be disallowed, but for me there is visual cues that property provides and if I'm declaring a number of public fields/functions I'd want the present them in a similar manner.
Feb 17 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, February 16, 2011 09:47:32 Jesse Phillips wrote:
 Dmitry Olshansky Wrote:
 Now to properties, this is actually shouldn't be allowed:
    property int hours;
 
  property is a annotation applied to functions (getter/setter), to allow 


 Why shouldn't it be allowed? While it provides no benefit it does document
 that it is a property.

Except that property is for _functions_. You mark a function with property so that it _acts_ like a variable. property on a variable is _meaningless_. It would be like marking a variable nothrow. It makes no sense. Neither should be legal. The fact that a member variable is public makes it a property. property on a member variable makes no sense. - Jonathan M Davis
Feb 16 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 16 Feb 2011 12:47:32 -0500, Jesse Phillips  
<jessekphillips+D gmail.com> wrote:

 Dmitry Olshansky Wrote:

 Now to properties, this is actually shouldn't be allowed:

    property int hours;

  property is a annotation applied to functions (getter/setter), to  
 allow calling it with omitted () and a natural assign syntax like this:

Why shouldn't it be allowed? While it provides no benefit it does document that it is a property.

Regardless of this, you should be aware that an invariant is not called when a public field is changed/accessed, whether it's marked with property or not. Only member functions invoke the invariant. -Steve
Feb 16 2011
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, February 17, 2011 10:39:20 Jesse Phillips wrote:
 Jonathan M Davis Wrote:
 Except that  property is for _functions_. You mark a function with
  property so that it _acts_ like a variable.  property on a variable is
 _meaningless_. It would be like marking a variable nothrow. It makes no
 sense. Neither should be legal. The fact that a member variable is
 public makes it a property.  property on a member variable makes no
 sense.
 
 - Jonathan M Davis

class Foo { property { int min; int hour() { return _hour;} ... } } I agree that useless markings should usually be disallowed, but for me there is visual cues that property provides and if I'm declaring a number of public fields/functions I'd want the present them in a similar manner.

Except that property on a variable does _nothing_. It's totally inappropriate. I really think that it should be a bug. It wouldn't make any sense to mark a variable as nothrow would it? A public member variable is both a property and nothrow by its very nature. Now, sadly enough, if you replace property with nothrow in the code above (and remove the ... and make sure that there's actually an _hour variable), it compiles just fine, so the compiler is being ridiculously lax about attributes that aren't valid. - Jonathan M Davis
Feb 17 2011