Thread overview
More than one invariant per struct/class
Aug 04, 2011
simendsjo
Aug 04, 2011
Pelle
Aug 04, 2011
simendsjo
Aug 04, 2011
Pelle
Aug 06, 2011
simendsjo
Aug 06, 2011
Jonathan M Davis
Aug 08, 2011
Pelle
Aug 08, 2011
simendsjo
August 04, 2011
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
}
August 04, 2011
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
August 04, 2011
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)?
August 04, 2011
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.
August 04, 2011
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. :--)
August 06, 2011
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..
August 06, 2011
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
August 08, 2011
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.
August 08, 2011
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