www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Struct initializers and const in 2.009

reply torhu <no spam.invalid> writes:
---
struct Foo
{
	int val;
}

struct Bar {
    Foo f;
    //const Foo f;  // workaround
}

const Foo foo = { 123 };  // line 11

const Bar bar = {
    f: foo         // the problem is here
};
---
bug.d(11): Error: cannot implicitly convert expression (Foo(123)) of 
type const(Foo) to Foo

The problem here is that Bar.f is not const, while foo is.  Since bar is 
const, shouldn't consts always be legal in the initializer? Or doesn't 
it work that way?

The workaround for this is pretty simple, I know.  foo could also be 
made an enum, but I need 1.x compatibility.
Jan 06 2008
next sibling parent Sean Kelly <sean f4.ca> writes:
torhu wrote:
 ---
 struct Foo
 {
     int val;
 }
 
 struct Bar {
    Foo f;
    //const Foo f;  // workaround
 }
 
 const Foo foo = { 123 };  // line 11
 
 const Bar bar = {
    f: foo         // the problem is here
 };
 ---
 bug.d(11): Error: cannot implicitly convert expression (Foo(123)) of 
 type const(Foo) to Foo
 
 The problem here is that Bar.f is not const, while foo is.  Since bar is 
 const, shouldn't consts always be legal in the initializer? Or doesn't 
 it work that way?
 
 The workaround for this is pretty simple, I know.  foo could also be 
 made an enum, but I need 1.x compatibility.

Weird. With transitive const, I'd expect the assignment to be from const(Foo) to const(Foo). Sean
Jan 06 2008
prev sibling parent reply torhu <no spam.invalid> writes:
Another surprise I got was when doing something like this:

---
struct Bar {
    int f;
}

const Bar bar = { 5 };

void f(in Bar b)
{
    Bar[3] array;
    array[0] = b;   // line 10
    //array[0] = *cast(Bar*)&b;  // ugly workaround
}


void main()
{
    f(bar);
}
---
bug2.d(10): Error: cannot implicitly convert expression (b) of type 
const(Bar) to Bar

The problem here is that f's parameter has to be 'in' or 'const', 
otherwise bar can't be used as an argument to f.  But a const Bar can't 
be assigned to an element of an array, since the elements cannot be 
const, or assigning to them would be disallowed.

So I guess mixing const and mutable structs is no longer viable as of 
2.009, they would have to be separate types.  But I guess that's the way 
transitive const has to be.  In this example, making bar an enum instead 
of a const would solve the issue, though.  I'm only doing this because 
I'm looking for an 1.0 compatible way of declaring struct consts like 
bar.  Maybe I should just remove const instead.

Trying to cast away the constness of f's b argument doesn't work either. 
  The compiler complains about a missing opCall when I do 'cast(Bar)b'. 
  Is that bug, or is a different syntax for casting away const needed?
Jan 06 2008
parent reply Dan <murpsoft hotmail.com> writes:
You actually managed to make your programs compatible with D 1.x and 2.x !?!?

I spent a good 40 minutes on my source, and ultimately realized it's impossible
for me to do so;

version(D_Version2)
  alias const(char)[] const_string;
else
  alias char[] const_string;

Value {
  const Value opIndex(const_string){
    bla bla 
  }
}

You can't alias out the const declaration for the function, and you can't get
rid of it in 2.x and still have the program work, let alone have the desired
functionality.

Only reason the strings work is 'cause Alan showed me.  : )
Jan 06 2008
parent reply torhu <no spam.invalid> writes:
Dan wrote:
 You actually managed to make your programs compatible with D 1.x and 2.x !?!?

Only some bindings to a C library, so no classes or const methods necessary.
 I spent a good 40 minutes on my source, and ultimately realized it's
impossible for me to do so;
 
 version(D_Version2)
   alias const(char)[] const_string;
 else
   alias char[] const_string;
 
 Value {
   const Value opIndex(const_string){
     bla bla 
   }
 }
 
 You can't alias out the const declaration for the function, and you can't get
rid of it in 2.x and still have the program work, let alone have the desired
functionality.

Maybe you could make it work with some casting, but it might not be worth it. The const_string alias will work if you use a string mixin: version(D_Version2) mixin("alias const(char)[] const_string;"); else alias char[] const_string; But are you sure you need this, won't the Phobos string alias work? It's defined in object.d.
Jan 07 2008
next sibling parent Christopher Wright <dhasenan gmail.com> writes:
torhu wrote:
 Dan wrote:
 You actually managed to make your programs compatible with D 1.x and 
 2.x !?!?

Only some bindings to a C library, so no classes or const methods necessary.
 I spent a good 40 minutes on my source, and ultimately realized it's 
 impossible for me to do so;

 version(D_Version2)
   alias const(char)[] const_string;
 else
   alias char[] const_string;

 Value {
   const Value opIndex(const_string){
     bla bla   }
 }

 You can't alias out the const declaration for the function, and you 
 can't get rid of it in 2.x and still have the program work, let alone 
 have the desired functionality.

Maybe you could make it work with some casting, but it might not be worth it. The const_string alias will work if you use a string mixin: version(D_Version2) mixin("alias const(char)[] const_string;"); else alias char[] const_string; But are you sure you need this, won't the Phobos string alias work? It's defined in object.d.

And then you can just do: static if (!is(typeof(string))) alias char[] string; Future-proofs in case your code works with Tango and it gets a string alias in the future.
Jan 07 2008
prev sibling parent Sean Kelly <sean f4.ca> writes:
torhu wrote:
 Dan wrote:
 You actually managed to make your programs compatible with D 1.x and 
 2.x !?!?

Only some bindings to a C library, so no classes or const methods necessary.
 I spent a good 40 minutes on my source, and ultimately realized it's 
 impossible for me to do so;

 version(D_Version2)
   alias const(char)[] const_string;
 else
   alias char[] const_string;

 Value {
   const Value opIndex(const_string){
     bla bla   }
 }

 You can't alias out the const declaration for the function, and you 
 can't get rid of it in 2.x and still have the program work, let alone 
 have the desired functionality.

Maybe you could make it work with some casting, but it might not be worth it. The const_string alias will work if you use a string mixin: version(D_Version2) mixin("alias const(char)[] const_string;"); else alias char[] const_string; But are you sure you need this, won't the Phobos string alias work? It's defined in object.d.

You don't need either one for the function parameter. Try this: ... opIndex( in char[] ) {} I've come to the conclusion that the string aliases are really of fairly little utility in D, since 'in' works just as well for specifying const behavior and is also 1.0 compatible. About the only place I've found myself using them for portable code is the return value of the toString routine, since there is no portable way to define a const return value other than an alias with string mixins, as above. Sean
Jan 07 2008