Thread overview
initializing immutable structs
Mar 26, 2010
Paul D. Anderson
Mar 26, 2010
bearophile
Mar 27, 2010
Simen kjaeraas
Mar 29, 2010
Paul D. Anderson
March 26, 2010
I want to initialize an immutable struct but I'm encountering two difficulties and I can't find the answer in the documentation. (Wouldn't it be nice if someone wrote a book?)

The primary difficulty is that I can't use a static initializer but need to use a constructor instead. But the constructor isn't allowed as it's non-constant expression. How do I declare the struct variable and initialize it separately?

The second difficulty is that when I declare it immutable I get a "can't implicitly convert an expression of type X to to immutable X" error. I tried an explicit cast and that didn't work.

I'm reasonably certain that this is a common idiom. I'm just trying to declare some constants to use later. What am I missing?

Thanks,

Paul

1st Difficulty -- I can't
March 26, 2010
Paul D. Anderson:
> The primary difficulty is that I can't use a static initializer but need to use a constructor instead. But the constructor isn't allowed as it's non-constant expression. How do I declare the struct variable and initialize it separately?
> 
> The second difficulty is that when I declare it immutable I get a "can't implicitly convert an expression of type X to to immutable X" error. I tried an explicit cast and that didn't work.

Do not use casts, forget they exist. In safe mode you can't use them.
Show us the code that doesn't work as you want, because I have no ESP powers.

This shows how you can use immutable structs:

struct Foo {
    int x, y;
    this(int xx, int yy) {
        this.x = xx;
        this.y = yy;
    }
}

immutable struct Bar {
    int x, y;
    this(int xx, int yy) {
        this.x = xx;
        this.y = yy;
    }
}

struct Spam {
    int x, y;
    immutable this(int xx, int yy) { // ?
        this.x = xx;
        this.y = yy;
    }
}

void main() {
    immutable Foo f1 = Foo(1, 2);
    auto f2 = immutable(Foo)(1, 2);
    Foo f3 = Foo(1, 2);
    immutable Foo f4 = f3;
    auto b1 = Bar(1, 2);
    Bar b2 = Bar(1, 2);

    Spam s1 = Spam(1, 2);
    s1.x = 10;
}

But s1 is not immutable, I don't know what "immutable this()" means.

Bye,
bearophile
March 27, 2010
On Fri, 26 Mar 2010 06:35:29 +0100, Paul D. Anderson
<paul.d.removethis.anderson@comcast.andthis.net> wrote:

> I want to initialize an immutable struct but I'm encountering two difficulties and I can't find the answer in the documentation. (Wouldn't it be nice if someone wrote a book?)

You mean like this?
http://www.amazon.com/dp/0321635361

> The primary difficulty is that I can't use a static initializer but need to use a constructor instead. But the constructor isn't allowed as it's non-constant expression. How do I declare the struct variable and initialize it separately?

If your constructor is not CTFE-able, you're basically out of luck. The
following kinda works, but will probably not survive optimizations, and is
a horrible hack to break the type system:

struct S {
	int n;
	this( int n ) {
		this.n = n;
	}
}

immutable S s = S( 4 );

void main( ) {
	void* v = cast( void* )&s;
	( *cast( S* )v ) = S( 4 );
}

> The second difficulty is that when I declare it immutable I get a "can't implicitly convert an expression of type X to to immutable X" error. I tried an explicit cast and that didn't work.

This is indeed correct. D has a three-part const system, with both mutable
and immutable implicitly castable to const, but nothing castable to
immutable or mutable.

Immutable basically means 'will never change'. Hence, assigning something
that can change (mutable) or something that might change (const) to an
immutable variable will not work.

If you have created a mutable or const struct and want to convert it to
immutable, make sure there are no references to it, and use
std.contract's AssumeUnique
http://www.digitalmars.com/d/2.0/phobos/std_contracts.html#assumeUnique

Conversion of POD structs (no pointer or class members) to immutable
should be painless, as they are pure value types and can be safely copied.

> I'm reasonably certain that this is a common idiom. I'm just trying to declare some constants to use later. What am I missing?
>
> Thanks,
>
> Paul
>
> 1st Difficulty -- I can't


-- 
Simen
March 29, 2010
Thanks for the help. assumeUnique only works on arrays, so it wasn't a solution for me but it did point me in the right direction.

I'm using a struct that contains a dynamic array as a member of another struct:

-----------------

Struct S {
  int a;
  int[] b;
}

Struct P {
  int c;
  S s;
}

-----------------

I was trying to do this:

-----------------

immutable S s1 = { a:234, b: [1] };

immutable P p1 = { c:100, s:s1);

-----------------

This is illegal since s1 is not the same type (immutable S) as the parameter (mutable S).

But this doesn't work:

-----------------

immutable P p1 = { c:100, s:'some constructor that returns s1');

-----------------

because the constructor is not constant, nor is it CTFE.

What did work:

-----------------

immutable S s1 = { a:234, b: [1] };

immutable P p1 = { c:100, s:cast(S) s1);

-----------------

Casting the immuatable as mutable so it can be assigned to another immutable variable.

However, having solved the problem, it has been such a hassle to have a mutable array that I'm looking into changing the design to make the array immutable. I'm running some timing tests to see what the performance tradeoff is.

Again, thanks

Paul


Simen kjaeraas Wrote:

> On Fri, 26 Mar 2010 06:35:29 +0100, Paul D. Anderson <paul.d.removethis.anderson@comcast.andthis.net> wrote:
> 
> > I want to initialize an immutable struct but I'm encountering two difficulties and I can't find the answer in the documentation. (Wouldn't it be nice if someone wrote a book?)
> 
> You mean like this?
> http://www.amazon.com/dp/0321635361
> 
> > The primary difficulty is that I can't use a static initializer but need to use a constructor instead. But the constructor isn't allowed as it's non-constant expression. How do I declare the struct variable and initialize it separately?
> 
> If your constructor is not CTFE-able, you're basically out of luck. The following kinda works, but will probably not survive optimizations, and is a horrible hack to break the type system:
> 
> struct S {
> 	int n;
> 	this( int n ) {
> 		this.n = n;
> 	}
> }
> 
> immutable S s = S( 4 );
> 
> void main( ) {
> 	void* v = cast( void* )&s;
> 	( *cast( S* )v ) = S( 4 );
> }
> 
> > The second difficulty is that when I declare it immutable I get a "can't implicitly convert an expression of type X to to immutable X" error. I tried an explicit cast and that didn't work.
> 
> This is indeed correct. D has a three-part const system, with both mutable and immutable implicitly castable to const, but nothing castable to immutable or mutable.
> 
> Immutable basically means 'will never change'. Hence, assigning something
> that can change (mutable) or something that might change (const) to an
> immutable variable will not work.
> 
> If you have created a mutable or const struct and want to convert it to immutable, make sure there are no references to it, and use std.contract's AssumeUnique http://www.digitalmars.com/d/2.0/phobos/std_contracts.html#assumeUnique
> 
> Conversion of POD structs (no pointer or class members) to immutable should be painless, as they are pure value types and can be safely copied.
> 
> > I'm reasonably certain that this is a common idiom. I'm just trying to declare some constants to use later. What am I missing?
> >
> > Thanks,
> >
> > Paul
> >
> > 1st Difficulty -- I can't
> 
> 
> -- 
> Simen