www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Run-time setting of immutable variable?

reply DLearner <bmqazwsx123 gmail.com> writes:
Suppose there is a variable that is set once per run, and is 
(supposed) never to be altered again.  However, the value to 
which it is set is not known at compile time.
Example below, variable is 'ArrPtr';
```
ubyte[10] Arr;

// immutable void* ArrPtr;
void* ArrPtr;

void main() {

    ArrPtr = cast(void*)Arr[0];

// <Lots of code depending on ArrPtr, but not supposed to modify 
ArrPtr>

}
```
Is there a way of getting D to guarantee that ArrPtr is never 
modified after
```
    ArrPtr = cast(void*)Arr[0];
```

Best regards
Sep 02 2021
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Sep 02, 2021 at 04:01:19PM +0000, DLearner via Digitalmars-d-learn
wrote:
 Suppose there is a variable that is set once per run, and is
 (supposed) never to be altered again.  However, the value to which it
 is set is not known at compile time.
This is the classic use case of `immutable`. Using the example you gave, you'd move the initialization of ArrPtr into a static module constructor: immutable void* ArrPtr; shared static this() { ArrPtr = ...; // initialize it here } void main() { ... // ArrPtr is immutable from here on. } T -- Дерево держится корнями, а человек - друзьями.
Sep 02 2021
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/2/21 12:01 PM, DLearner wrote:
 Suppose there is a variable that is set once per run, and is (supposed) 
 never to be altered again.  However, the value to which it is set is not 
 known at compile time.
 Example below, variable is 'ArrPtr';
 ```
 ubyte[10] Arr;
 
 // immutable void* ArrPtr;
 void* ArrPtr;
 
 void main() {
 
     ArrPtr = cast(void*)Arr[0];
 
 // <Lots of code depending on ArrPtr, but not supposed to modify ArrPtr>
 
 }
 ```
 Is there a way of getting D to guarantee that ArrPtr is never modified 
 after
 ```
     ArrPtr = cast(void*)Arr[0];
 ```]
You shouldn't be doing this. `Arr` is not immutable, so `ArrPtr` shouldn't point at it if it's immutable. If you want to guarantee that `ArrPtr` never changes once set, yet still want it to point at mutable data, you need to use a type that does that (like a head mutable or "write once" type), which I believe doesn't exist in phobos. If you don't actually need to mutate the data via `ArrPtr`, you can make it const, and use H.S. Teoh's solution. But you should not use immutable, as the compiler implies that data pointed at is also immutable (and of course, you won't need casting). Make sure you use regular `static this`, not `shared static this`, as your fields are thread-local, not shared. -Steve
Sep 02 2021
parent reply DLearner <bmqazwsx123 gmail.com> writes:
On Thursday, 2 September 2021 at 16:46:46 UTC, Steven 
Schveighoffer wrote:
 On 9/2/21 12:01 PM, DLearner wrote:
 Suppose there is a variable that is set once per run, and is 
 (supposed) never to be altered again.  However, the value to 
 which it is set is not known at compile time.
 Example below, variable is 'ArrPtr';
 ```
 ubyte[10] Arr;
 
 // immutable void* ArrPtr;
 void* ArrPtr;
 
 void main() {
 
     ArrPtr = cast(void*)Arr[0];
 
 // <Lots of code depending on ArrPtr, but not supposed to 
 modify ArrPtr>
 
 }
 ```
 Is there a way of getting D to guarantee that ArrPtr is never 
 modified after
 ```
     ArrPtr = cast(void*)Arr[0];
 ```]
You shouldn't be doing this. `Arr` is not immutable, so `ArrPtr` shouldn't point at it if it's immutable. If you want to guarantee that `ArrPtr` never changes once set, yet still want it to point at mutable data, you need to use a type that does that (like a head mutable or "write once" type), which I believe doesn't exist in phobos. If you don't actually need to mutate the data via `ArrPtr`, you can make it const, and use H.S. Teoh's solution. But you should not use immutable, as the compiler implies that data pointed at is also immutable (and of course, you won't need casting). Make sure you use regular `static this`, not `shared static this`, as your fields are thread-local, not shared. -Steve
The following clean-compiled and produced the expected result: ``` ubyte[10] Arr; immutable void* ArrPtr; shared static this() { ArrPtr = cast(immutable void*)(&Arr[0]); } void main() { import std.stdio; void* ArrPtr2; ArrPtr2 = cast(void*)(&Arr[0]); writeln("ArrPtr = ", ArrPtr); writeln("ArrPtr2 = ", ArrPtr2); // consistency test // ArrPtr = ArrPtr + 1; // mutability test - compile (correctly) failed when uncommented. ArrPtr2 = ArrPtr2 + 1; Arr[1] = 4; Arr[1] = 7; // mutability test } ``` The following produced deprecated warnings, but still seemed to work: ``` ubyte[10] Arr; immutable void* ArrPtr; static this() { ArrPtr = cast(immutable void*)(&Arr[0]); } void main() { import std.stdio; void* ArrPtr2; ArrPtr2 = cast(void*)(&Arr[0]); writeln("ArrPtr = ", ArrPtr); writeln("ArrPtr2 = ", ArrPtr2); // consistency test // ArrPtr = ArrPtr + 1; // mutability test on ArrPtr - compile (correctly) failed when uncommented. ArrPtr2 = ArrPtr2 + 1; Arr[1] = 4; Arr[1] = 7; // mutability test on Arr } ``` I am looking for a mutable Arr but would like an immutable ArrPtr. ``` `Arr` is not immutable, so `ArrPtr` shouldn't point at it if it's immutable. ``` Surely there is no inconsistency - at run time the array is in a fixed place, so ArrPtr is (or at least should be) a constant, but the contents of the array can vary as the program runs.
Sep 02 2021
next sibling parent Kagamin <spam here.lot> writes:
If you want only address, you can keep it as size_t:

	ubyte[10] Arr;
	immutable size_t Address;
	static this() {
		Address = cast(size_t)(&Arr[0]);
	}
Sep 02 2021
prev sibling next sibling parent jfondren <julian.fondren gmail.com> writes:
On Thursday, 2 September 2021 at 17:17:15 UTC, DLearner wrote:
 Surely there is no inconsistency - at run time the array is in 
 a fixed place,  so ArrPtr is (or at least should be) a 
 constant, but the contents of the array
 can vary as the program runs.
In the case of `immutable(T)* ArrPtr`, the contents of the pointed-to array cannot vary as the program runs. If it's immutable, nothing in the program ever mutates it. In the case of `const(T)* ArrPtr`, the contents of the pointed-to array can vary as the program runs, and the only restriction is that the array can't be mutated through ArrPtr. If what you mean is that you want the *pointer* to never change, `T * const ArrPtr` in C syntax, but that you don't care if the pointed-to array changes via ArrPtr or any other reference, then I don't think D can express this. You could make ArrPtr a function: ```d void main() { int[] xs = [1, 2, 3, 4]; int* p() { return &xs[2]; } p[0] = 0; assert(xs == [1, 2, 0, 4]); p++; // Error: ... not an lvalue and cannot be modified } ```
Sep 02 2021
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Sep 02, 2021 at 05:17:15PM +0000, DLearner via Digitalmars-d-learn
wrote:
[...]
 The following clean-compiled and produced the expected result:
 ```
     ubyte[10] Arr;
 
     immutable void* ArrPtr;
 	shared static this() {
 		ArrPtr = cast(immutable void*)(&Arr[0]);
 	}
Casting this to immutable is unsafe, because Arr is actually mutable. In D, const and immutable are transitive, so when you cast a pointer into immutable, you're basically promising that *both* the pointer *and* the data pointed to will never change. The compiler is free to assume that the data pointed to will never change, which may cause consistency problems if the data *does* change later. In cases like this, const is a better choice: const ensures that the pointer will not mutate and the pointed-to data cannot be mutated through this pointer, but the data *may* be mutated through another reference (e.g., by modifying Arr directly). [...]
 I am looking for a mutable Arr but would like an immutable ArrPtr.
In D, const and immutable are transitive, so you cannot do this (but see below).
 ```
 `Arr` is not immutable, so `ArrPtr` shouldn't point at it if it's
 immutable.
 ```
 Surely there is no inconsistency - at run time the array is in a fixed
 place,  so ArrPtr is (or at least should be) a constant, but the
 contents of the array can vary as the program runs.
In this case, what you want is const, not immutable. Const means you cannot modify the pointer, and you cannot mutate the data through this pointer, but you *can* modify the array from a mutable reference. T -- You are only young once, but you can stay immature indefinitely. -- azephrahel
Sep 02 2021
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/2/21 1:17 PM, DLearner wrote:

 I am looking for a mutable Arr but would like an immutable ArrPtr.
Then you want const not immutable. Here is the reason: ```d void main() { int x = 5; immutable int *ptr = cast(immutable int *)&x; assert(*ptr == 5); // ok x = 6; assert(*ptr == 5); // what happens here? } ``` Depending on optimizations and compiler constant folding, that second assert may pass. immutable means "I can never change and *everything I point at* can never change". The compiler is free to use this knowledge to avoid redoing calculations it has already done. I tknows that `*ptr == 5` already, and that can never change, so it just doesn't even bother with the second assert. However, make ptr *const*, and now not only do you not need the cast, but the second assert will fail as expected.
 ```
 `Arr` is not immutable, so `ArrPtr` shouldn't point at it if it's 
 immutable.
 ```
 Surely there is no inconsistency - at run time the array is in a fixed 
 place,  so ArrPtr is (or at least should be) a constant, but the 
 contents of the array
 can vary as the program runs.
In D, const and immutable are transitive, which means that you can't have a pointer that is const, but allows changing what it points at. So while a const pointer *may* work for your purposes, you may want a specialized type, or a property function. It depends on how you intend to use `ArrPtr`. Others have given good answers to this problem. -Steve
Sep 02 2021
parent DLearner <bmqazwsx123 gmail.com> writes:
On Thursday, 2 September 2021 at 23:12:28 UTC, Steven 
Schveighoffer wrote:

[...]
 immutable means "I can never change and *everything I point at* 
 can never change".
[...] If that is how the language defines the keyword 'immutable' when used in the definition of a pointer variable, then so be it. I would, however, suggest that the additional 'action-at-a-distance' implication (freezing not just the variable itself, but also it's target) is inconsistent with the definition of 'immutable' with other variable types. Surely it would be better to reserve 'immutable' on a pointer to mean simply set-once on the pointer itself (with no implications for whatever the pointer is pointing to), and another keyword ('blocked'?) for the current definition?
Sep 03 2021
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 9/2/21 9:01 AM, DLearner wrote:
 Suppose there is a variable that is set once per run, and is (supposed) 
 never to be altered again.
An accessor function can be a solution, which supports your other comment about data potentially mutating by other means: // Assume these are in a module // vvvvvvvvvvvvvvvvvvvvvvvvvvvv // This is private; you can even name it arr_. private ubyte[10] arr; // This is the accessor: public const(ubyte)* arrPtr() { return arr.ptr; } // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ void main() { *arrPtr = 42; // Compilation ERROR; good. } Ali
Sep 02 2021