www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - More than one invariant per struct/class

reply simendsjo <simendsjo gmail.com> writes:
I would like to use a template mixin to add some fields to a struct, but 
I'd also like the template to add additional invariant checks without 
having to remember to add this for all struct/classes that mixes in this 
code.

class C {
     int a;
}

mixin template EmbedC() {
     C _c;

     // oops.. more than one invariant
     invariant() {
         assert(_c);
     }

     void close() {
         _c = null;
     }
}

struct S {
     int i = 10;
     invariant() {
         assert(i >= 10);
     }

     mixin EmbedC!();
}

void main() {
     S s;
     s.close();
     s._c.a = 10; // access violation, but I want assertion from invariant
}
Aug 04 2011
next sibling parent =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 04-08-2011 11:32, simendsjo wrote:
 I would like to use a template mixin to add some fields to a struct, but
 I'd also like the template to add additional invariant checks without
 having to remember to add this for all struct/classes that mixes in this
 code.

 class C {
 int a;
 }

 mixin template EmbedC() {
 C _c;

 // oops.. more than one invariant
 invariant() {
 assert(_c);
 }

 void close() {
 _c = null;
 }
 }

 struct S {
 int i = 10;
 invariant() {
 assert(i >= 10);
 }

 mixin EmbedC!();
 }

 void main() {
 S s;
 s.close();
 s._c.a = 10; // access violation, but I want assertion from invariant
 }

This sounds reasonable and useful to me. - Alex
Aug 04 2011
prev sibling next sibling parent reply Pelle <pelle.mansson gmail.com> writes:
On Thu, 04 Aug 2011 11:32:03 +0200, simendsjo <simendsjo gmail.com> wrote:

 I would like to use a template mixin to add some fields to a struct, but  
 I'd also like the template to add additional invariant checks without  
 having to remember to add this for all struct/classes that mixes in this  
 code.

 class C {
      int a;
 }

 mixin template EmbedC() {
      C _c;

      // oops.. more than one invariant
      invariant() {
          assert(_c);
      }

      void close() {
          _c = null;
      }
 }

 struct S {
      int i = 10;
      invariant() {
          assert(i >= 10);
      }

      mixin EmbedC!();
 }

 void main() {
      S s;
      s.close();
      s._c.a = 10; // access violation, but I want assertion from  
 invariant
 }

What happens if you replace assert(_c) with assert(_c !is null)?
Aug 04 2011
next sibling parent simendsjo <simendsjo gmail.com> writes:
On 04.08.2011 12:30, Pelle wrote:
 On Thu, 04 Aug 2011 11:32:03 +0200, simendsjo <simendsjo gmail.com> wrote:

 I would like to use a template mixin to add some fields to a struct,
 but I'd also like the template to add additional invariant checks
 without having to remember to add this for all struct/classes that
 mixes in this code.

 class C {
 int a;
 }

 mixin template EmbedC() {
 C _c;

 // oops.. more than one invariant
 invariant() {
 assert(_c);
 }

 void close() {
 _c = null;
 }
 }

 struct S {
 int i = 10;
 invariant() {
 assert(i >= 10);
 }

 mixin EmbedC!();
 }

 void main() {
 S s;
 s.close();
 s._c.a = 10; // access violation, but I want assertion from invariant
 }

What happens if you replace assert(_c) with assert(_c !is null)?

The problem is that you cannot include more than one invariant() in a struct or class. struct S { invariant() {} invariant() {} // blows up } void main() {} I could easily change the design for my use case, but I don't see why this restriction exists. Perhaps some more experienced users can comment on this.
Aug 04 2011
prev sibling parent Pelle <pelle.mansson gmail.com> writes:
On Thu, 04 Aug 2011 12:40:48 +0200, simendsjo <simendsjo gmail.com> wrote:
 On 04.08.2011 12:30, Pelle wrote:
 What happens if you replace assert(_c) with assert(_c !is null)?

The problem is that you cannot include more than one invariant() in a struct or class.

IIRC assert(obj) gets rewritten to obj.__invariant() or something like that, which segfaults if obj is null. I thought that maybe that was why the code didn't work. :--)
Aug 04 2011
prev sibling parent reply simendsjo <simendsjo gmail.com> writes:
On 04.08.2011 11:32, simendsjo wrote:
 I would like to use a template mixin to add some fields to a struct, but
 I'd also like the template to add additional invariant checks without
 having to remember to add this for all struct/classes that mixes in this
 code.

 class C {
 int a;
 }

 mixin template EmbedC() {
 C _c;

 // oops.. more than one invariant
 invariant() {
 assert(_c);
 }

 void close() {
 _c = null;
 }
 }

 struct S {
 int i = 10;
 invariant() {
 assert(i >= 10);
 }

 mixin EmbedC!();
 }

 void main() {
 S s;
 s.close();
 s._c.a = 10; // access violation, but I want assertion from invariant
 }

Should I create a feature request to support more than one invariant? It's pretty obvious that it works as designed given the nice error message though..
Aug 06 2011
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday 06 August 2011 22:40:15 simendsjo wrote:
 On 04.08.2011 11:32, simendsjo wrote:
 I would like to use a template mixin to add some fields to a struct, but
 I'd also like the template to add additional invariant checks without
 having to remember to add this for all struct/classes that mixes in this
 code.
 
 class C {
 int a;
 }
 
 mixin template EmbedC() {
 C _c;
 
 // oops.. more than one invariant
 invariant() {
 assert(_c);
 }
 
 void close() {
 _c = null;
 }
 }
 
 struct S {
 int i = 10;
 invariant() {
 assert(i >= 10);
 }
 
 mixin EmbedC!();
 }
 
 void main() {
 S s;
 s.close();
 s._c.a = 10; // access violation, but I want assertion from invariant
 }

Should I create a feature request to support more than one invariant? It's pretty obvious that it works as designed given the nice error message though..

Feel free to create a feature request on it. It may even get the language changed. However, having more than one invariant complicates things a bit, since right now, it's easy for the runtime to just call the one invariant. If you had multiple invariants, they would have to be merged somehow by the compiler. It's completely doable, but it definitely complicates things, which is probably why it doesn't work that way now. If you wanted to be able to do it now though, I'd suggest that the mixins not have invariants but that they have functions which you then have to call in the invariant of the type that they're being mixed into. It's more error prone, since you could forget to call one of those functions in the invariant, but it allows you to have invariants of a sort in the mixed in code and still only have one invariant for the type. - Jonathan M Davis
Aug 06 2011
parent simendsjo <simendsjo gmail.com> writes:
On 06.08.2011 22:53, Jonathan M Davis wrote:
 On Saturday 06 August 2011 22:40:15 simendsjo wrote:
 On 04.08.2011 11:32, simendsjo wrote:
 I would like to use a template mixin to add some fields to a struct, but
 I'd also like the template to add additional invariant checks without
 having to remember to add this for all struct/classes that mixes in this
 code.

 class C {
 int a;
 }

 mixin template EmbedC() {
 C _c;

 // oops.. more than one invariant
 invariant() {
 assert(_c);
 }

 void close() {
 _c = null;
 }
 }

 struct S {
 int i = 10;
 invariant() {
 assert(i>= 10);
 }

 mixin EmbedC!();
 }

 void main() {
 S s;
 s.close();
 s._c.a = 10; // access violation, but I want assertion from invariant
 }

Should I create a feature request to support more than one invariant? It's pretty obvious that it works as designed given the nice error message though..

Feel free to create a feature request on it. It may even get the language changed. However, having more than one invariant complicates things a bit, since right now, it's easy for the runtime to just call the one invariant. If you had multiple invariants, they would have to be merged somehow by the compiler. It's completely doable, but it definitely complicates things, which is probably why it doesn't work that way now. If you wanted to be able to do it now though, I'd suggest that the mixins not have invariants but that they have functions which you then have to call in the invariant of the type that they're being mixed into. It's more error prone, since you could forget to call one of those functions in the invariant, but it allows you to have invariants of a sort in the mixed in code and still only have one invariant for the type. - Jonathan M Davis

http://d.puremagic.com/issues/show_bug.cgi?id=6453
Aug 08 2011
prev sibling parent Pelle <pelle.mansson gmail.com> writes:
On Sat, 06 Aug 2011 22:53:31 +0200, Jonathan M Davis <jmdavisProg gmx.com>  
wrote:

 Feel free to create a feature request on it. It may even get the language
 changed. However, having more than one invariant complicates things a  
 bit,
 since right now, it's easy for the runtime to just call the one  
 invariant. If
 you had multiple invariants, they would have to be merged somehow by the
 compiler. It's completely doable, but it definitely complicates things,  
 which
 is probably why it doesn't work that way now.

unittests are already merged this way, so it should be easy.
Aug 07 2011