September 05, 2019
05.09.2019 14:28, berni пишет:
> On Thursday, 5 September 2019 at 11:22:15 UTC, drug wrote:
>> 05.09.2019 14:17, berni пишет:
>>>> Point[long] q;
>>>>
>>>> q[1] = Point(3);
>>>
>>> Leads to:
>>>
>>>> test.d(7): Error: cannot modify struct q[1L] Point with immutable members
>>>
>>>
>> But why do you try to modify immutable data? What is your point? Could you describe you use case?
> 
> That's probably, what I don't understand. I've got a Point, which should not be modified. I put it in a container (q) and later I get it out there again. It should still be the same Point as before. I modify the container, not the Point, don't I?

One solution could be using either pointer to `const(Point)` or class here (to avoid pointer using) https://run.dlang.io/is/rfKKAJ

September 05, 2019
On Thursday, 5 September 2019 at 12:15:51 UTC, drug wrote:
> One solution could be using either pointer to `const(Point)` or class here (to avoid pointer using) https://run.dlang.io/is/rfKKAJ

OK. This are two solutions and although I'll probably not going to use any of those (due to other reasons), I still don't understand, why the original approach does not work. If I've got a book an put it in a box and later I'll get it out again, it's still the same book. So why has a struct changed when I put it into an AA and get it out again? It's not supposed to change...
September 05, 2019
05.09.2019 15:46, berni пишет:
> On Thursday, 5 September 2019 at 12:15:51 UTC, drug wrote:
>> One solution could be using either pointer to `const(Point)` or class here (to avoid pointer using) https://run.dlang.io/is/rfKKAJ
> 
> OK. This are two solutions and although I'll probably not going to use any of those (due to other reasons), I still don't understand, why the original approach does not work. If I've got a book an put it in a box and later I'll get it out again, it's still the same book. So why has a struct changed when I put it into an AA and get it out again? It's not supposed to change...
Because structs are value types so when you put it into an AA you modify old value and because it is const/immutable compiler gives an error.

But if you just want to initialize an AA by immutable members then this can be usefull to read https://dlang.org/spec/hash-map.html#runtime_initialization
September 05, 2019
On Thursday, 5 September 2019 at 13:27:55 UTC, drug wrote:
> [...]when you put it into an AA you modify old value

Why?!? :-o When putting it into an AA it will be copied to a different place in memory, but the value is still the same, it's not modified. Sorry, but I still think, there is something fundamentally wrong about how I think about immutability.

> But if you just want to initialize an AA by immutable members then this can be usefull to read https://dlang.org/spec/hash-map.html#runtime_initialization

Well, yes and no. I want to initialize an AA with structs that contain immutable members. And that AA resides at runtime inside of a function body. I don't see, how this can be done with he approach given by the link. :-(
September 05, 2019
05.09.2019 17:31, berni пишет:
> On Thursday, 5 September 2019 at 13:27:55 UTC, drug wrote:
>> [...]when you put it into an AA you modify old value
> 
> Why?!? :-o When putting it into an AA it will be copied to a different place in memory, but the value is still the same, it's not modified. Sorry, but I still think, there is something fundamentally wrong about how I think about immutability.
Because structs are value types - assigning new value to old value means the old value modification. In case of reference types like pointers or classes assigning new value to old one also means modifying old value but this old value is a reference to value so in case of reference types only reference modified but the value isn't

> 
>> But if you just want to initialize an AA by immutable members then this can be usefull to read https://dlang.org/spec/hash-map.html#runtime_initialization
> 
> Well, yes and no. I want to initialize an AA with structs that contain immutable members. And that AA resides at runtime inside of a function body. I don't see, how this can be done with he approach given by the link. :-(

September 05, 2019
On 09/05/2019 07:31 AM, berni wrote:
> On Thursday, 5 September 2019 at 13:27:55 UTC, drug wrote:
>> [...]when you put it into an AA you modify old value
>
> Why?!? :-o When putting it into an AA it will be copied to a different
> place in memory,

That's the misunderstanding: The existing object is assigned over. The address is the same:

void main() {
  int[int] aa;
  aa[1] = 1;
  const oldPointer = (1 in aa);
  aa[1] = 11;
  assert(oldPointer is (1 in aa));  // Passes
}

> but the value is still the same, it's not modified.

const or immutable members make structs unassignable.

Whether the members of a type are const or immutable should not be dictated by where the objects of that type will be used. If it makes sense otherwise, sure...

If you are worried about existing elements being modified, you can provide a different container that wraps an AA, but provides an opIndex that returns 'ref const(T)'. That would solve the immutability of the elements in the container.

Ali

September 05, 2019
On Thursday, 5 September 2019 at 15:48:40 UTC, Ali Çehreli wrote:
> That's the misunderstanding: The existing object is assigned over. The address is the same:
>
> void main() {
>   int[int] aa;
>   aa[1] = 1;
>   const oldPointer = (1 in aa);
>   aa[1] = 11;
>   assert(oldPointer is (1 in aa));  // Passes
> }

First, I thought, I've got understood it now, but then I wrote this little program and the result was not, what I thought it would be:

> void main()
> {
>     int[int] a;
>
>     immutable int b = 17;
>     a[1] = b;                          // <-- expecting error here
>     const oldPointer = (1 in a);
>     immutable int c = 10;
>     a[1] = c;
>     assert(oldPointer is (1 in a));
>
>     Point[int] d;
>
>     immutable Point e = Point(17);
>     d[1] = e;                           // <-- but error is here
> }
>
> struct Point
> {
>     immutable int x;
> }

What's the difference? I can put an immutable int in an AA and I can overwrite it (pointer is still the same), but I can't do that with a struct, having an immutable member. When I remove that immutable inside of the struct it works. ?!?

While writing this, I had an other idea, namely, that changing d[1] would make e to be something different (x inside Point is mutable this time):

> Point e = Point(17);
> d[1] = e;
> d[1] = Point(19);
> writeln(e);

But it's still 17.


> const or immutable members make structs unassignable.

But why? Here:

> Point[3] f;
> f[0] = Point(3);

I understand, that I cannot change f[0], because it's allready got a default value and that value would be overwritten. But in an aa, that member does not exist before putting the Point in there, hence there is nothing, that could be overwritten...

> Whether the members of a type are const or immutable should not be dictated by where the objects of that type will be used. If it makes sense otherwise, sure...

I'm not sure if I understand that right. It's sort of an advice on how to decide if one want's to make a member immutable or not, is it?

> If you are worried about existing elements being modified, you can provide a different container that wraps an AA, but provides an opIndex that returns 'ref const(T)'. That would solve the immutability of the elements in the container.

No, I don't worry about such things. My program runs smoothly when I don't make that members immutable. And I could perfectly live with that But that's the maxim I used the last three years: "If avoidable, don't use 'immutable' at all, it only causes problems." But that is not satisfiable. Because if immutable were that useless, why would it exist at all? So I would like to understand, what's happening; being able to predict, what works and what not. At the moment it's almost always the opposite of what I think it should be...

September 05, 2019
On 05.09.19 21:51, berni wrote:
>> void main()
>> {
>>     int[int] a;
>>
>>     immutable int b = 17;
>>     a[1] = b;                          // <-- expecting error here
>>     const oldPointer = (1 in a);
>>     immutable int c = 10;
>>     a[1] = c;
>>     assert(oldPointer is (1 in a));
>>
>>     Point[int] d;
>>
>>     immutable Point e = Point(17);
>>     d[1] = e;                           // <-- but error is here
>> }
>>
>> struct Point
>> {
>>     immutable int x;
>> }
> 
> What's the difference? I can put an immutable int in an AA and I can overwrite it (pointer is still the same),

You're not putting an immutable int into an AA. You're copying the value of an immutable int to a mutable one.

> but I can't do that with a struct, having an immutable member. When I remove that immutable inside of the struct it works. ?!?

`Point` is effectively the same as `immutable long`. A better simile would be this: `immutable(int)[int] a; a[1] = 17;`. And now you get the same error. You can't overwrite the element, because its immutable.

You could argue that there is no element before assigning (initializing) `d[1]` for the first time. So the assignment should go through the first time, and it should only be an error when you try to write a second time. But figuring that out mechanically is hard, and DMD isn't smart enough to do it. So, to be on the safe side, it just says that you can't do that at all.
September 05, 2019
On 09/05/2019 12:51 PM, berni wrote:

>>     int[int] a;
>>
>>     immutable int b = 17;
>>     a[1] = b;                          // <-- expecting error here

As explained elsewhere, a[1] is a mutable int. That assignment is copying b on top of the element.

>>     const oldPointer = (1 in a);
>>     immutable int c = 10;
>>     a[1] = c;
>>     assert(oldPointer is (1 in a));
>>
>>     Point[int] d;
>>
>>     immutable Point e = Point(17);
>>     d[1] = e;                           // <-- but error is here

That is the equivalent of

  d[1].x = e.x;

It can't work because the left-hand side is immutable. (immutable or const members make objects of those types unassignable.)

>> const or immutable members make structs unassignable.
>
> But why? Here:

Otherwise the immutability guarantees woul be violated.

I understand your questioning the AA design but at the lowest level it's just assignment operation. I understand that it could be "emplacement" on top of the existing element but the guarantees would be violated even then because the 'in' operator returns a pointer. Placing a new object on the same address would make existing pointer-holders unhappy.

> I understand, that I cannot change f[0], because it's allready got a
> default value and that value would be overwritten. But in an aa, that
> member does not exist before putting the Point in there, hence there is
> nothing, that could be overwritten...

Yeah, it's highly likely just assignment on a default-valued object.

>> Whether the members of a type are const or immutable should not be
>> dictated by where the objects of that type will be used. If it makes
>> sense otherwise, sure...
>
> I'm not sure if I understand that right. It's sort of an advice on how
> to decide if one want's to make a member immutable or not, is it?

If it makes for the type to have immutable (or const) members, then fine; with the understanding that objects of that type cannot be assigned or mutated any other way, we can define them like that. What I meant is, because we want to use such a type in an AA and we don't want the element to change should not dictate the type's members. Using in an AA should be yet another usage of the type.

> if immutable were that useless, why would it exist
> at all?

immutable is useful: You can have immutable objects, immutable AAs (different from what we are discussing here), etc.

You can use immutable at a different level: not members but their members can be immutable. For example, a 'string' member would not be immutable itself but its chars would be immutable. There is no problem in having an AA with types having such a member:

struct Person {
  string name;
}

You can assign to Person objects but their names are immutable. If you wanted a Person where the name should never change, then you could make a const(Person), immutable(Person), or provide read-only access to 'name', etc.

> So I would like to understand, what's happening; being able to
> predict, what works and what not. At the moment it's almost always the
> opposite of what I think it should be...

As a general rule, I never make members const or immutable; this is a guideline that I carried over from C++. A recent issue I had with const members in C++ has been silent skipping of move assignment of objects. Unless one uses functional programming style, that's how it should be in D as well. Otherwise, assignment is disabled and AAs don't work as expected because they use assignment under the hood as well.

Ali

September 06, 2019
On Thursday, 5 September 2019 at 12:46:06 UTC, berni wrote:
> OK. This are two solutions and although I'll probably not going to use any of those (due to other reasons), I still don't understand, why the original approach does not work. If I've got a book an put it in a box and later I'll get it out again, it's still the same book. So why has a struct changed when I put it into an AA and get it out again? It's not supposed to change...

Physical objects work like reference types. A place on bookshelf is at one coordinate and a book is at another coordinate, you don't copy the book, you fill a place on bookshelf with a reference to the book.