www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Implicit conversion of struct with methods to immutable in pure

reply Timoses <timosesu gmail.com> writes:
Why does this fail?

     struct F
     {
         int i;
         ushort _x;
         void x(ushort v) pure
         {_x = v;}
         ushort x() const
         { return _x; }
     }

     immutable F f1 = () pure {
     F lf = F();
     return lf; }();
     // Error: cannot implicitly convert expression delegate () => 
lf() of type F to immutable(F)

     F makeF() pure
     {
      	F lf = F();
         return lf;
     }
     immutable F f2 = makeF();
     // Error: cannot implicitly convert expression makeF() of 
type F to immutable(F)

Removing the methods in struct F compiles fine.

Background: I have a mixin(bitfields!(...)) in the struct which 
utilizes member functions.


/////////////
Idea:
Just found out that it works when making the struct static. But 
why does that help?

Is it because the compiler wouldn't be able to check whether 
methods in the struct are accessing non-immutable data in the 
enclosing context?
That would not make much sense though because the following works:

// Compiles fine!
int modi = 3;
void main ()
{
     static struct F
     {
         int var() immutable { return modi; } // accessing modi 
from module scope
     }
     immutable f = () pure { F f = F(); return f; }();
}

So my explanation wouldn't make sense, since why would it be okay 
to use module-scope data and not enclosing context data?

So where does that limitation come from that I implicitly convert 
a nested struct to immutable in a pure function?
Jul 16 2018
parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Monday, 16 July 2018 at 11:43:03 UTC, Timoses wrote:
 Why does this fail?
It doesn't. Not using DMD 2.081.1 under Windows, at least. I tried adding a bitfield since you mentioned it, but it compiles nicely for me. Which version of DMD are you using, and are you having the issues with the exact code you posted here? -- Simen
Jul 16 2018
parent reply Timoses <timosesu gmail.com> writes:
On Monday, 16 July 2018 at 12:00:57 UTC, Simen Kjærås wrote:
 On Monday, 16 July 2018 at 11:43:03 UTC, Timoses wrote:
 Why does this fail?
It doesn't. Not using DMD 2.081.1 under Windows, at least. I tried adding a bitfield since you mentioned it, but it compiles nicely for me. Which version of DMD are you using, and are you having the issues with the exact code you posted here? -- Simen
https://run.dlang.io/is/Pgs527 I'm on 2.080.1. But above is on latest 2.081.1 I believe. Note that the bottom code snippet in the original post does work, while the first one does not.
Jul 16 2018
next sibling parent Seb <seb wilzba.ch> writes:
On Monday, 16 July 2018 at 13:13:53 UTC, Timoses wrote:
 On Monday, 16 July 2018 at 12:00:57 UTC, Simen Kjærås wrote:
 On Monday, 16 July 2018 at 11:43:03 UTC, Timoses wrote:
 Why does this fail?
It doesn't. Not using DMD 2.081.1 under Windows, at least. I tried adding a bitfield since you mentioned it, but it compiles nicely for me. Which version of DMD are you using, and are you having the issues with the exact code you posted here? -- Simen
https://run.dlang.io/is/Pgs527 I'm on 2.080.1. But above is on latest 2.081.1 I believe. Note that the bottom code snippet in the original post does work, while the first one does not.
Yep, run.dlang.io automatically updates itself to the latest compiler (you can check this e.g. with -v).
Jul 16 2018
prev sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Monday, 16 July 2018 at 13:13:53 UTC, Timoses wrote:
 On Monday, 16 July 2018 at 12:00:57 UTC, Simen Kjærås wrote:
 On Monday, 16 July 2018 at 11:43:03 UTC, Timoses wrote:
 Why does this fail?
It doesn't. Not using DMD 2.081.1 under Windows, at least. I tried adding a bitfield since you mentioned it, but it compiles nicely for me. Which version of DMD are you using, and are you having the issues with the exact code you posted here? -- Simen
https://run.dlang.io/is/Pgs527 I'm on 2.080.1. But above is on latest 2.081.1 I believe. Note that the bottom code snippet in the original post does work, while the first one does not.
That makes sense. The problem is F has a context pointer to the main() block, since it's a non-static struct with methods inside a block. It doesn't actually use the context pointer for anything, so it possibly shouldn't have one, but it does, so we have to work around it. The fix is to mark F as static, or move it outside the main() block. -- Simen
Jul 16 2018
parent reply Timoses <timosesu gmail.com> writes:
On Tuesday, 17 July 2018 at 06:24:12 UTC, Simen Kjærås wrote:
 That makes sense. The problem is F has a context pointer to the 
 main() block, since it's a non-static struct with methods 
 inside a block. It doesn't actually use the context pointer for 
 anything, so it possibly shouldn't have one, but it does, so we 
 have to work around it.

 The fix is to mark F as static, or move it outside the main() 
 block.

 --
   Simen
Thanks for the explanation. But why is a context pointer a problem? Is it problematic because the context pointer to the main scope can not guarantee `immutable`? E.g. if I happened to use data from main in a function of the immutable struct then... well then what? The struct would still be immutable, but what would prevent a function from using non-immutable data? E.g. I could do this int gnumber = 3; struct F { int i; void fun() immutable { gnumber = 5; } } void main () { immutable F f = F(); f.fun; } I declared `fun()` to be an immutable function. So calling the immutable struct function `F.fun()` changes a module scope int. The same could be applied to local data of the main scope, however the following fails: void main () { int mnumber = 3; struct F { int i; void fun() immutable { // Error: immutable function onlineapp.main.F.fun cannot access mutable data mnumber mnumber = 5; } } immutable F f = F(); f.fun; } Is this connected why I can't implicitly convert a local struct with a context pointer to immutable? What's the reason behind it?
Jul 18 2018
parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Wednesday, 18 July 2018 at 11:28:54 UTC, Timoses wrote:
 But why is a context pointer a problem? Is it problematic 
 because the context pointer to the main scope can not guarantee 
 `immutable`? E.g. if I happened to use data from main in a 
 function of the immutable struct then... well then what?
 The struct would still be immutable, but what would prevent a 
 function from using non-immutable data?
It's a known bug: https://issues.dlang.org/show_bug.cgi?id=18563 In the associated discussion (https://forum.dlang.org/thread/p7lp2b$1jod$1 digitalmars.com), Steven Schveighoffer points out that an immutable struct may be passed to other threads, which would give one thread access to another thread's stack. This could be a good enough reason to prevent this kind of conversion, but a better error message would still make sense. -- Simen
Jul 18 2018
parent Timoses <timosesu gmail.com> writes:
On Thursday, 19 July 2018 at 06:35:36 UTC, Simen Kjærås wrote:
 On Wednesday, 18 July 2018 at 11:28:54 UTC, Timoses wrote:
 But why is a context pointer a problem? Is it problematic 
 because the context pointer to the main scope can not 
 guarantee `immutable`? E.g. if I happened to use data from 
 main in a function of the immutable struct then... well then 
 what?
 The struct would still be immutable, but what would prevent a 
 function from using non-immutable data?
It's a known bug: https://issues.dlang.org/show_bug.cgi?id=18563 In the associated discussion (https://forum.dlang.org/thread/p7lp2b$1jod$1 digitalmars.com), Steven Schveighoffer points out that an immutable struct may be passed to other threads, which would give one thread access to another thread's stack. This could be a good enough reason to prevent this kind of conversion, but a better error message would still make sense. -- Simen
Thanks so much for the pointer, Simen. Interesting discussion.
Jul 19 2018