www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - immutable/mutable aliasing

reply "Jet" <1092501151 qq.com> writes:
void foo(immutable int* x, int* y) {
  bar(*x); // bar(3)
  *y = 4;  // undefined behavior
  bar(*x); // bar(??)
}
...
int i = 3;
foo(cast(immutable)&i, &i);
----------------------------------
In the 2.065 version, I can compile. But that is not in the 
documentation.
Jul 03 2014
next sibling parent reply "Jet" <1092501151 qq.com> writes:
There, how to distinguish between const and immutable? thank 
you~:)

/**
"Const types are like immutable types, except that const forms a 
read-only view of data. Other aliases to that same data may 
change it at any time. "

"Any data referenced by the const declaration cannot be changed 
from the const declaration, but it might be changed by other 
references to the same data. "
**/

Can sample code, please?
Jul 03 2014
next sibling parent "anonymous" <anonymous example.com> writes:
On Thursday, 3 July 2014 at 21:06:12 UTC, Jet wrote:
 There, how to distinguish between const and immutable? thank 
 you~:)

 /**
 "Const types are like immutable types, except that const forms 
 a read-only view of data. Other aliases to that same data may 
 change it at any time. "

 "Any data referenced by the const declaration cannot be changed 
 from the const declaration, but it might be changed by other 
 references to the same data. "
 **/

 Can sample code, please?
When you replace 'immutable' with 'const' in your sample code, then there is no undefined behaviour, and no cast is needed. void foo(const int* x, int* y) { bar(*x); // bar(3) *y = 4; // perfectly fine bar(*x); // bar(4) } void main() { int i = 3; foo(&i, &i); // no cast }
Jul 03 2014
prev sibling parent reply "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Thu, Jul 03, 2014 at 09:06:11PM +0000, Jet via Digitalmars-d-learn wrote:
 There, how to distinguish between const and immutable? thank you~:)
 
 /**
 "Const types are like immutable types, except that const forms a
 read-only view of data. Other aliases to that same data may change it
 at any time. "
 
 "Any data referenced by the const declaration cannot be changed from
 the const declaration, but it might be changed by other references to
 the same data. "
 **/
 
 Can sample code, please?
This diagram may help understand D's const/immutable system: const / \ (mutable) immutable Mutable is the default unqualified type. It means you're free to modify it. Immutable is the opposite: it is guaranteed that neither you, nor anybody else, can modify it. Once an immutable value is initialized, it might as well be "cast in stone", it can never change again. int x = 1; // mutable x++; // OK immutable int y = 1; //y++; // ILLEGAL: cannot modify immutable Const is the bridge between mutable and immutable. It means that *you* cannot change the value, but somebody else might. The reason we want const is so that you can pass both a mutable or an immutable value to the same function. The function cannot change the value, but the caller can, if it's mutable. (And of course, immutable cannot be changed by anyone -- which is OK, since the function isn't allowed to change a const parameter anyway.) class MyData { int x; } auto data = new MyData; // mutable data.x++; // OK auto idata = new immutable(MyData); //idata.x++; // ILLEGAL: cannot modify immutable bool myFunc(const(MyData) obj) { obj.x++; // ILLEGAL: cannot modify const return obj.x > 0; // OK: can read const } bool b1 = myFunc(data); // OK, can pass mutable to const bool b2 = myFunc(idata); // OK, can pass immutable to const // (since myFunc cannot modify it) void cache(immutable(MyData) iobj) { static immutable(MyData) _cache; _cache = iobj; } cache(data); // ILLEGAL: cannot pass mutable to immutable cache(idata); // OK: can pass immutable to immutable Usually, you'd write function parameters to be const rather than immutable, because you want to accept both mutable and immutable arguments. But sometimes, you want to be 100% sure that nobody outside the function can modify the value while you're using it. For example: int longCalculation(const(MyData) obj) { int acc = 0; foreach (i; 0 .. 1_000_000) { acc += obj.x; } return acc; } auto evil = MyData(1); spawn((const(MyData) d) { // This runs in a different thread writeln(longCalculation(d)); }, evil); evil.x = 5; // Oops Since "evil" is mutable, it's allowed to be passed to a const parameter: it just means that longCalculation cannot modify it. However, that doesn't guarantee that somebody else can't modify it; for example, in the above code we run longCalculation in a different thread, and then we set evil.x = 5 in the main thread. The result is that the value of obj.x in longCalculation gets mutated while the loop is running, causing the result to become corrupted. So the child thread will *not* print "1000000", but something else, depending on the relative timing of the threads. To prevent this sort of problems, the solution is to make longCalculation take an immutable parameter. Then if you try to compile it, the compiler will complain that you can't pass mutable to immutable, so you're forced to make "evil" either const or immutable. Which means that the "evil.x = 5" line will be rejected by the compiler because nobody is allowed to modify an immutable value, thus preventing the corruption problem. T -- Truth, Sir, is a cow which will give [skeptics] no more milk, and so they are gone to milk the bull. -- Sam. Johnson
Jul 03 2014
parent "Jet" <1092501151 qq.com> writes:
Awesome!!!
Thank you so much!
Jul 03 2014
prev sibling next sibling parent reply "anonymous" <anonymous example.com> writes:
On Thursday, 3 July 2014 at 20:43:33 UTC, Jet wrote:
 void foo(immutable int* x, int* y) {
  bar(*x); // bar(3)
  *y = 4;  // undefined behavior
  bar(*x); // bar(??)
 }
 ...
 int i = 3;
 foo(cast(immutable)&i, &i);
 ----------------------------------
 In the 2.065 version, I can compile. But that is not in the 
 documentation.
It's undefined behaviour, which means: don't do it. Your sample compiles, because you're casting. By casting you're saying "shut up compiler, I know what I'm doing". See also: http://dlang.org/const3.html - "Removing Immutable With A Cast"
Jul 03 2014
parent "Jet" <1092501151 qq.com> writes:
Thank you all. These answers are very detailed. I think I learned 
a lot.
Jul 03 2014
prev sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 07/03/2014 01:43 PM, Jet wrote:

 void foo(immutable int* x, int* y) {
   bar(*x); // bar(3)
   *y = 4;  // undefined behavior
   bar(*x); // bar(??)
 }
 ...
 int i = 3;
 foo(cast(immutable)&i, &i);
 ----------------------------------
 In the 2.065 version, I can compile. But that is not in the 
documentation. In addition to the excellent responses in this thread, this is how I like to describe the semantics between const versus immutable references (including pointers) on a function interface: - const reference or pointer parameter: "I will not modify your data." - immutable reference or pointer parameter: "I demand data from you that nobody will modify." When the semantics are described that way, they are not related at all: One is a promise to the caller, the other is a request from the caller. Ali
Jul 03 2014