www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - self-referential invariant member

reply "Neil Vice" <psgdg swiftdsl.com.au> writes:
I am attempting to provide a constant instance of a struct as a member of 
the struct (in 2.010) and am getting unexpected compiler errors. Can someone 
explain what the compiler thinks I'm trying to do here and/or how I'd go 
about achieving what I want if it's possible?

The following code:

    struct Test
    {
        public invariant Test Default;
    }

    void main()
    {
        Test test = Test.Default;
    }

produces the following compiler output:

    test.d(3): struct test.Test unable to resolve forward reference in 
definition

Similarly if Test is declared as a class not a struct the compiler produces 
the following:

    test.d(9): Error: 'this' is only allowed in non-static member functions, 
not main
    test.d(9): Error: this for Default needs to be type Test not type int
    test.d(9): Error: cannot implicitly convert expression (this.Default) of 
type invariant(Test) to test.Test

If Default is declared as a manifest constant using the enum keyword the 
compiler gets a stack overflow (bug #1800).

If I attempt to initialise Default (where Test is a struct), the compiler 
makes reference to opCall:

    public invariant Test Default = {};

yields:

    test.d(9): Error: no property 'opCall' for type 'Test'
    test.d(9): Error: function expected before (), not 1 of type int
    test.d(9): Error: cannot implicitly convert expression (1(Default)) of 
type int to Test
Feb 06 2008
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Neil Vice" wrote
I am attempting to provide a constant instance of a struct as a member of 
the struct (in 2.010) and am getting unexpected compiler errors. Can 
someone explain what the compiler thinks I'm trying to do here and/or how 
I'd go about achieving what I want if it's possible?

 The following code:

    struct Test
    {
        public invariant Test Default;
    }

    void main()
    {
        Test test = Test.Default;
    }

Invariant members are not automatically static (though they should be). The compiler is choking because it can't determine what a 'Test' is because you are defining it as a member of each instance. In addition, you are going to have problems on Test test = Test.Default because you are not allowed to automatically copy an invariant or const struct to a mutable struct in case the struct has a pointer in it. However, I think Walter and co. are working on getting this to work. What you probably want to do is: enum Test Default = {...}; as enum is now the preferred method for manifest constants. -Steve
Feb 06 2008
parent "Neil Vice" <psgdg swiftdsl.com.au> writes:
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message 
news:focfbh$2qn0$1 digitalmars.com...
 "Neil Vice" wrote
I am attempting to provide a constant instance of a struct as a member of 
the struct (in 2.010) and am getting unexpected compiler errors. Can 
someone explain what the compiler thinks I'm trying to do here and/or how 
I'd go about achieving what I want if it's possible?

 The following code:

    struct Test
    {
        public invariant Test Default;
    }

    void main()
    {
        Test test = Test.Default;
    }

Invariant members are not automatically static (though they should be). The compiler is choking because it can't determine what a 'Test' is because you are defining it as a member of each instance.

Hmm I did try declaring them specifically static as well but with no success. Given that the documentation for invariants didn't include any static examples (which I expected to be a pretty standard case) I assumed they were automatically static.
 In addition, you are going to have problems on Test test = Test.Default 
 because you are not allowed to automatically copy an invariant or const 
 struct to a mutable struct in case the struct has a pointer in it. 
 However, I think Walter and co. are working on getting this to work.

Yeah I'm really struggling to work with the current const system. There are some constructs they just don't work well with (e.g. opApply) and as much as I love the safety provided by const/invariant declarations I think I've still yet to be successful in actually finding a use for them that doesn't require an explicit duplication. Having said that, are structs not copied on assignment in D? I would have expected the assignment to duplicate Test.Default at least for structs.
 What you probably want to do is:

 enum Test Default = {...};

 as enum is now the preferred method for manifest constants.

That was the solution I came to, but as mentioned in my previous post this causes the compiler to crash with a stack overflow; obviously this will eventually be fixed. Why two methods for defining consts are required though I don't understand. Why should there be any difference between an invariant and an enum-style manifest const? Along similar lines I don't see the reason to have a "ref const" variable. Should consts not automatically be passed by reference as an optimisation? Are "in" parameters really passed by value (though I guess the distinction is only for structs)? I also wish I understood what was going on with the compiler trying to access opCall when I attempt access an invariant declared as follows: public invariant Test Default = {}; I wonder if it relates to the property/method dichotemy or whether it's treating {} as an inline delegate even though there's no way to initialise a Test to a delegate... Thanks for your reply, Neil
Feb 06 2008
prev sibling parent reply Denton Cockburn <diboss hotmail.com> writes:
On Wed, 06 Feb 2008 22:57:53 +0900, Neil Vice wrote:

 I am attempting to provide a constant instance of a struct as a member of 
 the struct (in 2.010) and am getting unexpected compiler errors. Can someone 
 explain what the compiler thinks I'm trying to do here and/or how I'd go 
 about achieving what I want if it's possible?
 
 The following code:
 
     struct Test
     {
         public invariant Test Default;
     }
 
     void main()
     {
         Test test = Test.Default;
     }
 
 produces the following compiler output:
 
     test.d(3): struct test.Test unable to resolve forward reference in 
 definition
 
 Similarly if Test is declared as a class not a struct the compiler produces 
 the following:
 
     test.d(9): Error: 'this' is only allowed in non-static member functions, 
 not main
     test.d(9): Error: this for Default needs to be type Test not type int
     test.d(9): Error: cannot implicitly convert expression (this.Default) of 
 type invariant(Test) to test.Test
 
 If Default is declared as a manifest constant using the enum keyword the 
 compiler gets a stack overflow (bug #1800).
 
 If I attempt to initialise Default (where Test is a struct), the compiler 
 makes reference to opCall:
 
     public invariant Test Default = {};
 
 yields:
 
     test.d(9): Error: no property 'opCall' for type 'Test'
     test.d(9): Error: function expected before (), not 1 of type int
     test.d(9): Error: cannot implicitly convert expression (1(Default)) of 
 type int to Test

You need to define your struct with a static opCall to handle an invariant Test: Also, Default has to be declared static. struct Test { public static invariant Test Default; static Test opCall(invariant Test t) { // create, do stuff to, and return struct } } I think that opCall will have to be set up to copy that Default; Isn't what you want a ref to that Default struct? I thought assigning a struct is equivalent to copying it. I got it to compile doing what I just did. So again, are you trying to have copies of the Default, or just one copy?
Feb 08 2008
parent "Neil Vice" <psgdg swiftdsl.com.au> writes:
"Denton Cockburn" <diboss hotmail.com> wrote in message 
news:pan.2008.02.08.12.52.58.37333 hotmail.com...
 On Wed, 06 Feb 2008 22:57:53 +0900, Neil Vice wrote:

 I am attempting to provide a constant instance of a struct as a member of
 the struct (in 2.010) and am getting unexpected compiler errors. Can 
 someone
 explain what the compiler thinks I'm trying to do here and/or how I'd go
 about achieving what I want if it's possible?

 The following code:

     struct Test
     {
         public invariant Test Default;
     }

     void main()
     {
         Test test = Test.Default;
     }

 produces the following compiler output:

     test.d(3): struct test.Test unable to resolve forward reference in
 definition

 Similarly if Test is declared as a class not a struct the compiler 
 produces
 the following:

     test.d(9): Error: 'this' is only allowed in non-static member 
 functions,
 not main
     test.d(9): Error: this for Default needs to be type Test not type int
     test.d(9): Error: cannot implicitly convert expression (this.Default) 
 of
 type invariant(Test) to test.Test

 If Default is declared as a manifest constant using the enum keyword the
 compiler gets a stack overflow (bug #1800).

 If I attempt to initialise Default (where Test is a struct), the compiler
 makes reference to opCall:

     public invariant Test Default = {};

 yields:

     test.d(9): Error: no property 'opCall' for type 'Test'
     test.d(9): Error: function expected before (), not 1 of type int
     test.d(9): Error: cannot implicitly convert expression (1(Default)) 
 of
 type int to Test

You need to define your struct with a static opCall to handle an invariant Test:

I can't assign an invariant struct to a mutable struct variable without explicitly implementing a copy operator (opCall)?!
 Also, Default has to be declared static.

Yeh, I had incorrectly assumed invariants were static.
 I think that opCall will have to be set up to copy that Default;
 Isn't what you want a ref to that Default struct?  I thought assigning
 a struct is equivalent to copying it.

The struct only wraps a ulong so a copy is just fine. I also thought assigning a struct should be equivalent to copying it, but from this exercise it would seem that that is only the case if you explicitly implement opCall to perform the task. Given the nature of structs, copying using a method rather than a straight binary copy strikes me as not only appallingly slow but a significant inconvenience to the developer =( Again I could be missing something... Incidently, DMD often spits out the most confusing error messages that (to me) are seemingly unrelated to the actualy problem even when explained to me. With no other language/compiler have I had so much trouble tracking down errors of this nature.
Feb 09 2008