www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - immutable ctors, immutable members, and TDPL

reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
An interesting subject is being debated by some of the heavy hitters of D  
on the latest beta on the announce NG.

However, I have found that there is an inconsistency in TDPL that needs to  
be addressed.

Forgetting the controversy currently brewing, we have the following  
current situation:

struct S
{
    immutable int x;
    this(int n)
    {
       x = n;
       int y = x;
       x = 0;
    }
}

This compiles, and shows that one can use an immutable, and then the  
immutable can be changed.  This is no good, for obvious reasons.

TDPL does not specifically address this issue (from what I can find via  
manual search), but it does talk about immutable constructors.  It's  
prescription is for immutable constructors to be prohibited from reading  
any members, and prohibited from calling any functions with 'this' as a  
parameter.  You are allowed to write the members as many times as you  
want.  The idea is if you can't read the data, it can't be inconsistent.

Note that this mechanism is not currently implemented in the compiler.

I thought "great, let's apply the same technique here".  But we have a  
problem.  It would be too restrictive to say you can't call another member  
function or any other function in a *normal* ctor, just because you  
declared an immutable member.  An immutable member is generally set once  
and then read from then on.

I think both mechanisms (protecting immutable members in the ctor, and  
protecting all members in an immutable ctor) should be consistent.  I  
think the 'no calling any functions' restriction is to restrictive to  
apply to normal ctors.

My leaning is to re-define how immutable ctors and normal ctors that can  
initialize immutable members should behave.  The immutability should be  
applied on the first read of the member, or calling a member  
function/passing 'this' somewhere.  Some flow analysis is required for  
this, but we can be pretty conservative about it.  There aren't too many  
use cases for this stuff anyway.

What do you think?

-Steve
May 23 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/23/2013 08:41 AM, Steven Schveighoffer wrote:

 The immutability should be applied on the first read of the
 member,
Makes sense to me. Not exactly the same issue but here is a related past discussion: http://forum.dlang.org/thread/khu6tl$q8o$1 digitalmars.com Quoting deadalnix: "Yes, in general, first assignment in a constructor should be considered as a declaration if the value is not read before. This allow for the mentioned optimization, but many very other important stuff as well, like the construction of immutable objects." And the enhancement request: http://d.puremagic.com/issues/show_bug.cgi?id=9732 Ali
May 23 2013
parent Kenji Hara <k.hara.pg gmail.com> writes:
2013/5/24 Ali =C3=87ehreli <acehreli yahoo.com>

 On 05/23/2013 08:41 AM, Steven Schveighoffer wrote:

 The immutability should be applied on the first read of the
 member,
Makes sense to me. Not exactly the same issue but here is a related past discussion: http://forum.dlang.org/thread/**khu6tl$q8o$1 digitalmars.com<http://for=
um.dlang.org/thread/khu6tl$q8o$1 digitalmars.com>
 Quoting deadalnix:

 "Yes, in general, first assignment in a constructor should be
 considered as a declaration if the value is not read before.

 This allow for the mentioned optimization, but many very other
 important stuff as well, like the construction of immutable
 objects."

 And the enhancement request:

   http://d.puremagic.com/issues/**show_bug.cgi?id=3D9732<http://d.puremag=
ic.com/issues/show_bug.cgi?id=3D9732> Enh 9732 is a dup of bug 9665? http://d.puremagic.com/issues/show_bug.cgi?id=3D9665 Kenji Hara
May 23 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, May 23, 2013 11:41:29 Steven Schveighoffer wrote:
 An interesting subject is being debated by some of the heavy hitters of D
 on the latest beta on the announce NG.
 
 However, I have found that there is an inconsistency in TDPL that needs to
 be addressed.

 What do you think?
Sounds sensible to me. I thought that that's how it worked anyway (clearly, I remember wrong - I should probably reread TDPL again one of these days soon, as I sometimes forget little tidbits like this). Sometimes, keeping all of this straight can be quite difficult when you start getting down to the nitty gritty details. - Jonathan M Davis
May 23 2013
prev sibling next sibling parent "Dicebot" <m.strashun gmail.com> writes:
On Thursday, 23 May 2013 at 15:41:32 UTC, Steven Schveighoffer 
wrote:
 ...
 What do you think?

 -Steve
Honestly, I don't know. It is quite a complex question for me to grasp at once. Only thing I have a string feeling about is that those two cases should be smiliar from the point of type system ("a" type is the same in constructed variables): struct S1 { int a; } struct S2 { immutable int a; } // ... auto s1 = immutable(S1)(); auto s2 = S2();
May 24 2013
prev sibling next sibling parent reply "Dicebot" <m.strashun gmail.com> writes:
Also one issue Don has brought my attention to is this snippet:

// -----------------------------

immutable int x = 1;

void main()
{
	import std.stdio;
	writeln(x);
}

static this()
{
	x = 42;
}
// (does not compile in 2.062 and won't in 2.063)

// ------------------------------

Whatever approach is taken, I think it should be consistent with 
structs/classes in a sense that global variables are module 
members and module constructor is, well, constructor.

But it looks very hard to do because "immutable" is implicitly 
"shared". Ideas?
May 24 2013
next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 24 May 2013 at 08:47:40 UTC, Dicebot wrote:
 But it looks very hard to do because "immutable" is implicitly 
 "shared". Ideas?
I think that module constructor are pain and suffering. Anyway, this should not work if the ctor isn't shared.
May 24 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Friday, 24 May 2013 at 08:47:40 UTC, Dicebot wrote:
 Also one issue Don has brought my attention to is this snippet:

 // -----------------------------

 immutable int x = 1;

 void main()
 {
 	import std.stdio;
 	writeln(x);
 }

 static this()
 {
 	x = 42;
 }
 // (does not compile in 2.062 and won't in 2.063)

 // ------------------------------

 Whatever approach is taken, I think it should be consistent 
 with structs/classes in a sense that global variables are 
 module members and module constructor is, well, constructor.

 But it looks very hard to do because "immutable" is implicitly 
 "shared". Ideas?
That shouldn't compile because the non-shared module constructor writes to the shared variable x whenever a new thread starts with that module. But a better question is whether or not it should compile with a shared module constructor: immutable int x = 1; shared static this() { x = 42; } ... I don't know, but I think it should follow the same logic as with a non-static immutable member variable and a shared default constructor. Also, I think the following shouldn't compile due to a non-shared module constructor assigning to a shared variable (currently it does compile): immutable int x; static this() { import std.random; x = uniform(0, 100); }
May 24 2013
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 24 May 2013 04:47:38 -0400, Dicebot <m.strashun gmail.com> wrote:

 Also one issue Don has brought my attention to is this snippet:

 // -----------------------------

 immutable int x = 1;

 void main()
 {
 	import std.stdio;
 	writeln(x);
 }

 static this()
 {
 	x = 42;
 }
 // (does not compile in 2.062 and won't in 2.063)

 // ------------------------------

 Whatever approach is taken, I think it should be consistent with  
 structs/classes in a sense that global variables are module members and  
 module constructor is, well, constructor.
This is not what I am looking to fix. Module ctors are very different from struct ctors. Also, I specifically avoided the "pre-initialized" values, because that is outside the scope of this problem. We assume that for the sake of this argument, the value is uninitialized before the ctor is called.
 But it looks very hard to do because "immutable" is implicitly "shared".  
 Ideas?
Use shared static this, and the runtime should run your module ctors in dependency order. That is, another module that uses x must have this module's ctors run before it. -Steve
May 24 2013
parent "Dicebot" <m.strashun gmail.com> writes:
On Friday, 24 May 2013 at 13:56:06 UTC, Steven Schveighoffer 
wrote:
 Use shared static this, and the runtime should run your module 
 ctors in dependency order.  That is, another module that uses x 
 must have this module's ctors run before it.

 -Steve
Oh, awesome! I did not know this. Well, than modules can somewhat mimic struct/class behavior. They are not the same, but they try to look similar in other parts of language (for example, protection attributes) and (in my opinion!) should try the same here.
May 24 2013
prev sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Thursday, 23 May 2013 at 15:41:32 UTC, Steven Schveighoffer 
wrote:
 An interesting subject is being debated by some of the heavy 
 hitters of D on the latest beta on the announce NG.

 However, I have found that there is an inconsistency in TDPL 
 that needs to be addressed.

 Forgetting the controversy currently brewing, we have the 
 following current situation:

 struct S
 {
    immutable int x;
    this(int n)
    {
       x = n;
       int y = x;
       x = 0;
    }
 }

 This compiles, and shows that one can use an immutable, and 
 then the immutable can be changed.  This is no good, for 
 obvious reasons.
I think immutable is something you cannot change. Also, the reverse is true, if you can change something, it's not immutable. According to this logic, x is not immutable inside the scope of the constructor, because you *can* change it. Therefore it should be so that: import std.traits; struct S { immutable int x; this(int n) { static assert(isMutable!(typeof(x))); } } static assert(!isMutable!(typeof(S.init.x)));
May 24 2013