Thread overview |
---|
January 03, 2015 cannot modify struct with immutable members | ||||
---|---|---|---|---|
| ||||
I get the following error from the code below: (dmd2.066.1, linux) test.d(26): Error: cannot modify struct myTest1 Test with immutable members Is this expected? If so, how can I achieve this result - being able to set (a new) initial value of myTest1 from within an nested function ? thanks ! ted code: struct A { int someInt; } struct Test { this( ref const(A) arg ) { mA = arg; } private: const(A) mA; } void main() { Test myTest1; A topA; void _someFunc( ref const(A) myA ) { myTest1 = Test(myA); } Test myTest2 = Test(topA); // is ok as expected _someFunc( topA ); // error. } |
January 03, 2015 Re: cannot modify struct with immutable members | ||||
---|---|---|---|---|
| ||||
Posted in reply to ted Attachments: | On Sat, 03 Jan 2015 13:25:31 +1030 ted via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com> wrote: > > I get the following error from the code below: (dmd2.066.1, linux) > test.d(26): Error: cannot modify struct myTest1 Test with immutable members > > Is this expected? > > If so, how can I achieve this result - being able to set (a new) initial value of myTest1 from within an nested function ? > > thanks ! > ted > > > code: > struct A > { > int someInt; > } > > struct Test > { > this( ref const(A) arg ) > { > mA = arg; > } > > private: > const(A) mA; > } > > void main() > { > Test myTest1; > A topA; > > void _someFunc( ref const(A) myA ) > { > myTest1 = Test(myA); > } > > Test myTest2 = Test(topA); // is ok as expected > _someFunc( topA ); // error. > } the question is: "why do you want `mA` to be const?" leaving aside compiler complaints this is the one and important question. let's try to fix your code instead of devising workarounds to beat the compiler. ;-) please remember that D `const` is not the same as C/C++ `const`, so my question is not so stupid as it may look. p.s. you can use `in A myA` instead of `ref const A myA`, in most cases compiler is intelligent enough to use "pass-by-reference" for `in` args. |
January 03, 2015 Re: cannot modify struct with immutable members | ||||
---|---|---|---|---|
| ||||
Posted in reply to ketmar | Hi, thanks for the reply...to answer your direct question, the original code looked like: struct A { int someInt; } struct Test { @property { const(A) getA() { return mA; } } this( ref const(A) arg ) { mA = arg; } private: A mA; } void main() { Test myTest1; A topA; void _someFunc( ref const(A) myA ) { myTest1 = Test(myA); } Test myTest2 = Test(topA); // is ok as expected _someFunc( topA ); // later on.... A foo = myTest1.getA(); } which compiles. However, I think I exercised some other compiler-related bug when I added a field to another structure in the module, and the compiler started complaining about the construct above....... 'Error: cannot implicitly convert expression (arg) of type const(A) to A' in the constructor of Test (I'm unable to recreate this error in this simple code example). (I am prototyping something, so the code I'm producing is very badly structured, and I have nested functions within delegates within .... and I have also hit some odd scoping errors - definite compiler issues - (notwithstanding the horrible code structure)). ....so (given my D knowledge is limited) I then wondered why it accepted (nonconst)mA=(const)arg in the first place, hence the const()...hence the original question. I am assuming that the ref const(A) myA means that _someFunc (and below) is unable to alter any fields of myA. This may be my basic error. thanks ! ketmar via Digitalmars-d-learn wrote: > On Sat, 03 Jan 2015 13:25:31 +1030 > ted via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com> wrote: > >> >> I get the following error from the code below: (dmd2.066.1, linux) >> test.d(26): Error: cannot modify struct myTest1 Test with immutable members >> >> Is this expected? >> >> If so, how can I achieve this result - being able to set (a new) initial value of myTest1 from within an nested function ? >> >> thanks ! >> ted >> >> >> code: >> struct A >> { >> int someInt; >> } >> >> struct Test >> { >> this( ref const(A) arg ) >> { >> mA = arg; >> } >> >> private: >> const(A) mA; >> } >> >> void main() >> { >> Test myTest1; >> A topA; >> >> void _someFunc( ref const(A) myA ) >> { >> myTest1 = Test(myA); >> } >> >> Test myTest2 = Test(topA); // is ok as expected >> _someFunc( topA ); // error. >> } > > the question is: "why do you want `mA` to be const?" leaving aside compiler complaints this is the one and important question. let's try to fix your code instead of devising workarounds to beat the compiler. ;-) > > please remember that D `const` is not the same as C/C++ `const`, so my question is not so stupid as it may look. > > p.s. you can use `in A myA` instead of `ref const A myA`, in most cases compiler is intelligent enough to use "pass-by-reference" for `in` args. |
January 03, 2015 Re: cannot modify struct with immutable members | ||||
---|---|---|---|---|
| ||||
Posted in reply to ted | Well, I just cleared up some of my misunderstanding. I did not realise the mA (within struct Test) would be a _copy_ of arg, not a reference (pointer) to arg. So the more correct code snippet would be: struct A { int someInt; } struct Test { @property { const(A) getA() { return *mA; } } this( in A arg ) { mA = &arg; } private: const A* mA; } void main() { Test myTest1; A topA; topA.someInt = 100; void _someFunc( in A myA ) { myTest1 = Test(myA); } Test myTest2 = Test(topA); // is ok as expected _someFunc( topA ); } which fails to compile for the same reason (test.d(30): Error: cannot modify struct myTest1 Test with immutable members) (I have been able to work around my original issue by removing @safe from Test, and then cast()ing ... but this is ugly) This code snippet is me trying to understand whether I have a fundamental misunderstanding with const, or whether it is an issue with the compiler (I agree with your view that 'fixing my code' is the correct approach, btw - I'm still curious). (The reason for this basic structure is that _someFunc is a callback from another module, and myTest1 contains state information that is created/adjusted via the callback. And (to be safe) myTest1 contains references to other structures that it should not adjust - hence the const()). ....and I can't use @safe and pointers...... So, it appears I need to do what I want with classes, not structs: i.e. import std.stdio; class A { int someInt; } @safe class Test { @property { const(A) getA() { return mA; } } this( in A arg ) { mA = arg; } private: const A mA; } void main() { Test myTest1; A topA = new A; topA.someInt = 100; void _someFunc( in A myA ) { myTest1 = new Test(myA); } Test myTest2 = new Test(topA); // is ok as expected _someFunc( topA ); writeln( "topA: ", topA.someInt ); writeln( "myTest1.A: ", myTest1.getA.someInt ); } I'm happy I've got a workaround (which seems to safely preserve the const'dness), but I still don't understand why the compiler barfs on the struct version as it should be 'replacing' the higher scoped variable.... anyway...thanks for your response.....apologies for the streaming conciousness of this reply....... |
January 03, 2015 Re: cannot modify struct with immutable members | ||||
---|---|---|---|---|
| ||||
Posted in reply to ted Attachments: | On Sat, 03 Jan 2015 14:45:24 +1030 ted via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com> wrote: > Well, I just cleared up some of my misunderstanding. > > I did not realise the mA (within struct Test) would be a _copy_ of arg, not a reference (pointer) to arg. > > So the more correct code snippet would be: > > struct A > { > int someInt; > } > > struct Test > { > @property { const(A) getA() { return *mA; } } > this( in A arg ) > { > mA = &arg; > } > > private: > const A* mA; > } > > void main() > { > Test myTest1; > A topA; > > topA.someInt = 100; > > void _someFunc( in A myA ) > { > myTest1 = Test(myA); > } > > Test myTest2 = Test(topA); // is ok as expected > _someFunc( topA ); > > > } nonononono! ;-) please, don't use pointers like this. try to avoid pointers altogether, they are VERY dangerous. as for your sample: it is already invalid. see: this (in A arg) { mA = &arg; } you are storing the address of *local* *var* *from* *stack* here. then local will go out of scope and... BANG! everyone is dead. > This code snippet is me trying to understand whether I have a fundamental misunderstanding with const, or whether it is an issue with the compiler seems that you didn't get D `const`. it's deffers from C/C++ `const`. in most cases you don't need to use it at all. the funny thing of D const is that const "variable" cannot be changed in any way after assigning. that's why compiler complains: you're trying to change variable with `const` part, which is forbidden. structure instance with const fields can be initialized only once, upon creation. so did `Test myTest1;` -- you initialized `myTest1` with default values. you can't reinitialize it later. in C++ constness on member doesn't impose such restrictions. this is confusing for newcomers with C/C++ expirience. the best advice here is "don't use `const` in D unless you are fully understand what you are doing and how it work in D". > I'm happy I've got a workaround (which seems to safely preserve the const'dness), but I still don't understand why the compiler barfs on the struct version as it should be 'replacing' the higher scoped variable.... you don't need `const` here at all. as far as i can see you want to tell the compiler that `mA` must not be changed after creating a struct. to achieve that you'd better move your struct to separate module and provide read-only getter. you need to move your struct to separate module 'cause `private` modifier will not affect the code in the same module. one of the D rules is that the code in one module can access anything that was declared in the same module, including "private" members of structs/classes. C++ tries to achieve that with "friend" members, but as D has full-fledged module system, it doesn't need such tricks. tl;dr: don't use `const` here, provide an accessor and stop worrying/helping the compiler. ;-) |
January 03, 2015 Re: cannot modify struct with immutable members | ||||
---|---|---|---|---|
| ||||
Posted in reply to ted Attachments: | On Sat, 03 Jan 2015 14:45:24 +1030 ted via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com> wrote: p.s. also please note that structs in D are always passed by value and copied (until you not explicitly ask for something another). so: MyStruct a; MyStruct b; b = a; actually does `memcpy()` (with postblit if there is any). and it's forbidden to overwrite `const` variable contents. that's why compiler complains: by assigning to `mA` you are trying to overwrite contents of `const` variable. |
January 03, 2015 Re: cannot modify struct with immutable members | ||||
---|---|---|---|---|
| ||||
Posted in reply to ketmar | ketmar via Digitalmars-d-learn wrote: > On Sat, 03 Jan 2015 14:45:24 +1030 > ted via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com> wrote: > >> Well, I just cleared up some of my misunderstanding. >> >> I did not realise the mA (within struct Test) would be a _copy_ of arg, >> not a reference (pointer) to arg. >> >> So the more correct code snippet would be: >> >> struct A >> { >> int someInt; >> } >> >> struct Test >> { >> @property { const(A) getA() { return *mA; } } >> this( in A arg ) >> { >> mA = &arg; >> } >> >> private: >> const A* mA; >> } >> >> void main() >> { >> Test myTest1; >> A topA; >> >> topA.someInt = 100; >> >> void _someFunc( in A myA ) >> { >> myTest1 = Test(myA); >> } >> >> Test myTest2 = Test(topA); // is ok as expected >> _someFunc( topA ); >> >> >> } > nonononono! ;-) > please, don't use pointers like this. try to avoid pointers altogether, > they are VERY dangerous. as for your sample: it is already invalid. see: > > this (in A arg) { mA = &arg; } > > you are storing the address of *local* *var* *from* *stack* here. then local will go out of scope and... BANG! everyone is dead. Oops...true (*blush*) - should have noticed this. > >> This code snippet is me trying to understand whether I have a fundamental misunderstanding with const, or whether it is an issue with the compiler > seems that you didn't get D `const`. it's deffers from C/C++ `const`. in most cases you don't need to use it at all. the funny thing of D const is that const "variable" cannot be changed in any way after assigning. that's why compiler complains: you're trying to change variable with `const` part, which is forbidden. > > structure instance with const fields can be initialized only once, upon creation. so did `Test myTest1;` -- you initialized `myTest1` with default values. you can't reinitialize it later. > > in C++ constness on member doesn't impose such restrictions. this is confusing for newcomers with C/C++ expirience. the best advice here is "don't use `const` in D unless you are fully understand what you are doing and how it work in D". Ironically, I'm trying to use const in an effort to understand it...but there seems to be an unusual amount of pain until I grok it. > >> I'm happy I've got a workaround (which seems to safely preserve the const'dness), but I still don't understand why the compiler barfs on the struct version as it should be 'replacing' the higher scoped variable.... > you don't need `const` here at all. as far as i can see you want to tell the compiler that `mA` must not be changed after creating a struct. to achieve that you'd better move your struct to separate module and provide read-only getter. > > you need to move your struct to separate module 'cause `private` modifier will not affect the code in the same module. one of the D rules is that the code in one module can access anything that was declared in the same module, including "private" members of structs/classes. C++ tries to achieve that with "friend" members, but as D has full-fledged module system, it doesn't need such tricks. > > tl;dr: don't use `const` here, provide an accessor and stop worrying/helping the compiler. ;-) Yeah.....its one of those cases where the prototype code is getting too ugly, and a refactorisation is required.....but no time !! many thanks, ted |
January 03, 2015 Re: cannot modify struct with immutable members | ||||
---|---|---|---|---|
| ||||
Posted in reply to ted Attachments: | On Sat, 03 Jan 2015 15:56:58 +1030 ted via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com> wrote: > Ironically, I'm trying to use const in an effort to understand it...but there seems to be an unusual amount of pain until I grok it. just remember that `const` "infects" everything down to the bytes when it's applied. and it's forbidden to overwrite `const` vars with different values. in your canse it "infects" your `A` struct, effectively converting it to `const A` (with `const int someInt`). and as you can't change "consted" value, and structs are `memcpy()`ed... compiler tracked that down and refused to do it. so you don't really need `const` fields in D. you can make getters `const` though, so that they can be used on `const MyStruct` instances. so two rules should help you here: 1. it's forbidden to overwrite `const` vars with new values. 2. `const` will infect everything down to bytes. maybe this will help you like it helps me. ;-) |
January 03, 2015 Re: cannot modify struct with immutable members | ||||
---|---|---|---|---|
| ||||
Posted in reply to ketmar | ketmar via Digitalmars-d-learn wrote:
> On Sat, 03 Jan 2015 15:56:58 +1030
> ted via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com> wrote:
>
>> Ironically, I'm trying to use const in an effort to understand it...but there seems to be an unusual amount of pain until I grok it.
> just remember that `const` "infects" everything down to the bytes when it's applied. and it's forbidden to overwrite `const` vars with different values.
>
> in your canse it "infects" your `A` struct, effectively converting it to `const A` (with `const int someInt`). and as you can't change "consted" value, and structs are `memcpy()`ed... compiler tracked that down and refused to do it.
>
> so you don't really need `const` fields in D. you can make getters `const` though, so that they can be used on `const MyStruct` instances.
>
> so two rules should help you here:
> 1. it's forbidden to overwrite `const` vars with new values.
> 2. `const` will infect everything down to bytes.
>
> maybe this will help you like it helps me. ;-)
Thanks for your help....besides the issues that you pointed out, I had forgotten that structs are always copied (I'm so used to thinking in pointers (if you ignore the fubar from my earlier example) - and a world where copying data structures is an expensive exercise to be avoided).......
I'm now taking the view that const is there for the compiler to optimise code on the basis that nothing can alter it once set (and can only be set on initialisation). So I see your point that it would not be used very often in general defensive code - better to provide access restrictions (getters) for most cases.
I am refactoring the code to use getters/setters....
One of the really good things about D is that it is relatively painless to refactor when you have to - much less boilerplate to have to move around !
thanks again,
regards,
ted
|
January 03, 2015 Re: cannot modify struct with immutable members | ||||
---|---|---|---|---|
| ||||
Posted in reply to ted Attachments: | On Sat, 03 Jan 2015 16:40:14 +1030 ted via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com> wrote: > I'm now taking the view that const is there for the compiler to optimise code on the basis that nothing can alter it once set (and can only be set on initialisation). So I see your point that it would not be used very often in general defensive code - better to provide access restrictions (getters) for most cases. exactly! ;-) > thanks again, you're welcome. hope you will keep enjoying D, it's great. ;-) |
Copyright © 1999-2021 by the D Language Foundation