www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Non-transitive immutable? Read only struct.

reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
So, I get it, head-const has been discussed to death before. But 
it seems to me that it is more of a problem that there is no (to 
my awareness) non-transitive immutable. If there is, I apologize.

So, there are at least 4 situations where you really want that:

1. Protect fields in structs/classes after initialization. 
Reduces bugs. Documents intent.

2. Turn received values from functions into something that cannot 
be modified reliably irrespective of what the protection the 
called function has set for it. Reduces bugs.

3. To have sensible immutable tuples that can point to 
non-immutable things. In my view, a must have.

4. To have structures in ROM that can point to memory mapped 
registers or RAM. Not a must have, but sensible.

I'm not saying that immutable should change, but that there is 
need for something in addition to that. Call it "readonly" if you 
want.
Dec 05 2019
next sibling parent reply Gregor =?UTF-8?B?TcO8Y2ts?= <gregormueckl gmx.de> writes:
On Thursday, 5 December 2019 at 17:01:07 UTC, Ola Fosheim Grøstad 
wrote:
 So, I get it, head-const has been discussed to death before. 
 But it seems to me that it is more of a problem that there is 
 no (to my awareness) non-transitive immutable. If there is, I 
 apologize.

 So, there are at least 4 situations where you really want that:

 1. Protect fields in structs/classes after initialization. 
 Reduces bugs. Documents intent.

 2. Turn received values from functions into something that 
 cannot be modified reliably irrespective of what the protection 
 the called function has set for it. Reduces bugs.

 3. To have sensible immutable tuples that can point to 
 non-immutable things. In my view, a must have.

 4. To have structures in ROM that can point to memory mapped 
 registers or RAM. Not a must have, but sensible.

 I'm not saying that immutable should change, but that there is 
 need for something in addition to that. Call it "readonly" if 
 you want.
Can you clarify how this goes beyond the classic OO pattern of private member variables with public getters and no setters? If there was a class-private visibility, D could emulate everything except point 3 on your list, I think, albeit somewhat verbosely. So how is your thinking diverging from that?
Dec 06 2019
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Friday, 6 December 2019 at 08:45:15 UTC, Gregor Mückl wrote:
 Can you clarify how this goes beyond the classic OO pattern of 
 private member variables with public getters and no setters? If 
 there was a class-private visibility, D could emulate 
 everything except point 3 on your list, I think, albeit 
 somewhat verbosely. So how is your thinking diverging from that?
You cannot easily emulate it since this is low-level typing where you can obtain the address of the memory and that memory should be read only within its lifetime. The problem with "immutable" is that it requires that read only memory only can point to read only memory, which is too limiting. (You can try to set up a big machinery of emulating pointers etc, but then you are basically implementing a new type system within the type system. Which probably will be too cumbersome and therefore not used.)
Dec 06 2019
prev sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Thursday, 5 December 2019 at 17:01:07 UTC, Ola Fosheim Grøstad 
wrote:

 1. Protect fields in structs/classes after initialization. 
 Reduces bugs. Documents intent.
immutable fields can be initialized in constructors. Getters allow you to define an interface that doesn't allow modification by outside forces while still allowing the class/struct to modify the fields if it feels like it, allowing both non-reassignable fields and lazy initialization.
 2. Turn received values from functions into something that 
 cannot be modified reliably irrespective of what the protection 
 the called function has set for it. Reduces bugs.
Const does this. If you know it's immutable call assumeUnique on it. If you want to limit modification in some ways while allowing it in other ways, that sounds like a library thing, not something the language should do for you.
 3. To have sensible immutable tuples that can point to 
 non-immutable things. In my view, a must have.
Getters can be used for this.
 4. To have structures in ROM that can point to memory mapped 
 registers or RAM. Not a must have, but sensible.
Getters can do this. You'll probably have to dip into some un- safe code, but this seems like an exotic enough use case that we can live with that. -- Simen
Dec 06 2019
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Friday, 6 December 2019 at 09:11:11 UTC, Simen Kjærås wrote:
 On Thursday, 5 December 2019 at 17:01:07 UTC, Ola Fosheim 
 Grøstad wrote:

 1. Protect fields in structs/classes after initialization. 
 Reduces bugs. Documents intent.
immutable fields can be initialized in constructors.
But immutable fields cannot contain pointers to non-immutable memory?
 Getters allow you to define an interface that doesn't allow 
 modification by outside forces while still allowing the 
 class/struct to modify the fields if it feels like it, allowing 
 both non-reassignable fields and lazy initialization.
Making fields/attributes read only is not only for the external interface it is also documentation for internal use, to prevent accidental modification in the implementation, prevent inheritance issues, enables caching based on typing in generic programming.
 2. Turn received values from functions into something that 
 cannot be modified reliably irrespective of what the 
 protection the called function has set for it. Reduces bugs.
Const does this. If you know it's immutable call assumeUnique on it. If you want to limit modification in some ways while allowing it in other ways, that sounds like a library thing, not something the language should do for you.
No, const does not do it. If you receive a mutable value it will be const, not immutable. If you use immutable it will fail if the value contains an immutable pointer. (I am not talking about returned references, but value copies) So there is no easy way to write this kind of code that has increased robustness in evolving codebases.
 3. To have sensible immutable tuples that can point to 
 non-immutable things. In my view, a must have.
Getters can be used for this.
That does not make the memory immutable as seen from the compiler?
 4. To have structures in ROM that can point to memory mapped 
 registers or RAM. Not a must have, but sensible.
Getters can do this. You'll probably have to dip into some un- safe code, but this seems like an exotic enough use case that we can live with that.
Casting away immutable sounds very dangerous. If that can be done then the optimizer cannot use immutable for anything? Anyway, getters are not useful in low level programming. You need to be able to take the address of the memory. So what you are left with is to leave it mutable to the typesystem and never write to it in your code, so basically no help from the type system.
Dec 06 2019
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Friday, 6 December 2019 at 09:26:40 UTC, Ola Fosheim Grøstad 
wrote:
 4. To have structures in ROM that can point to memory mapped 
 registers or RAM. Not a must have, but sensible.
Getters can do this. You'll probably have to dip into some un- safe code, but this seems like an exotic enough use case that we can live with that.
Casting away immutable sounds very dangerous. If that can be done then the optimizer cannot use immutable for anything? Anyway, getters are not useful in low level programming. You need to be able to take the address of the memory. So what you are left with is to leave it mutable to the typesystem and never write to it in your code, so basically no help from the type system.
I guess you could use const for ROM, but that might affect caching and ROM can be slow.
Dec 06 2019
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
I guess I should have stated more clearly to major optimization 
advantages of having more memory set as immutable:

1. It allows the compiler to assume that there is no aliasing.

2. It allows the compiler to retain loaded values 
(registers/stack) even accross invalidation/barriers.

3. It allows generic code to retain cached copies of 
values/pointers obtained through a chain of immutable. Including 
pointers to mutable memory.
Dec 06 2019