Thread overview
self-referential invariant member
Feb 06, 2008
Neil Vice
Feb 07, 2008
Neil Vice
Feb 08, 2008
Denton Cockburn
Feb 09, 2008
Neil Vice
February 06, 2008
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




February 06, 2008
"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


February 07, 2008
"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


February 08, 2008
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?
February 09, 2008
"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.