digitalmars.D.learn - immutable/mutable aliasing
- Jet (11/11) Jul 03 2014 void foo(immutable int* x, int* y) {
- Jet (11/11) Jul 03 2014 There, how to distinguish between const and immutable? thank
- anonymous (13/24) Jul 03 2014 When you replace 'immutable' with 'const' in your sample code,
- H. S. Teoh via Digitalmars-d-learn (76/89) Jul 03 2014 This diagram may help understand D's const/immutable system:
- Jet (2/2) Jul 03 2014 Awesome!!!
- anonymous (6/17) Jul 03 2014 It's undefined behaviour, which means: don't do it. Your sample
- Jet (2/2) Jul 03 2014 Thank you all. These answers are very detailed. I think I learned
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (11/21) Jul 03 2014 documentation.
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
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
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
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
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
Thank you all. These answers are very detailed. I think I learned a lot.
Jul 03 2014
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 thedocumentation. 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