digitalmars.D.learn - getting rid of immutable (or const)
- berni (9/22) Sep 05 2019 The type of q is immutable(long). But I need a mutable q. I found
- Daniel Kozak (4/26) Sep 05 2019 in this case you can just use:
- Andrew Edwards (3/35) Sep 05 2019 or:
- berni (5/30) Sep 05 2019 Ahh, great! :-)
- berni (2/5) Sep 05 2019 Found the answer myself: q.map!(a=>a.x).minElement; :-)
- berni (9/21) Sep 05 2019 Here the compiler complains with:
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (12/19) Sep 05 2019 https://dlang.org/library/std/range/retro.html
- berni (4/10) Sep 05 2019 OK. Then here's the next one:
- drug (3/12) Sep 05 2019 But why do you try to modify immutable data? What is your point? Could
- berni (5/18) Sep 05 2019 That's probably, what I don't understand. I've got a Point, which
- drug (3/22) Sep 05 2019 One solution could be using either pointer to `const(Point)` or class
- berni (7/10) Sep 05 2019 OK. This are two solutions and although I'll probably not going
- drug (6/16) Sep 05 2019 Because structs are value types so when you put it into an AA you modify...
- berni (9/13) Sep 05 2019 Why?!? :-o When putting it into an AA it will be copied to a
- drug (6/22) Sep 05 2019 Because structs are value types - assigning new value to old value means...
- =?UTF-8?Q?Ali_=c3=87ehreli?= (19/24) Sep 05 2019 That's the misunderstanding: The existing object is assigned over. The
- berni (29/70) Sep 05 2019 First, I thought, I've got understood it now, but then I wrote
- ag0aep6g (12/39) Sep 05 2019 You're not putting an immutable int into an AA. You're copying the value...
- berni (4/12) Sep 06 2019 Ah, the point is not, that my object contains an immutable
- =?UTF-8?Q?Ali_=c3=87ehreli?= (40/69) Sep 05 2019 As explained elsewhere, a[1] is a mutable int. That assignment is
- berni (10/23) Sep 06 2019 So, what I'm just trying all the time is not to have a struct
- Kagamin (5/12) Sep 06 2019 Physical objects work like reference types. A place on bookshelf
- berni (4/8) Sep 06 2019 So it's more like a piece of paper, where there is place for a
I still struggle with the concept of immutable and const:import std.stdio; void main() { auto p = Point(3); auto q = p.x; writeln(typeof(q).stringof); } struct Point { property immutable long x; }The type of q is immutable(long). But I need a mutable q. I found two ways: a) long q = p.x; b) auto q = cast(long)p.x; Either way I've to specify the type "long" which I dislike (here it's not a real burdon, but with more complicated types it might be). Is there a way, to make q mutable without having to write the type explicitly?
Sep 05 2019
On Thu, Sep 5, 2019 at 9:55 AM berni via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:I still struggle with the concept of immutable and const:in this case you can just use: auto q = cast()p.x;import std.stdio; void main() { auto p = Point(3); auto q = p.x; writeln(typeof(q).stringof); } struct Point { property immutable long x; }The type of q is immutable(long). But I need a mutable q. I found two ways: a) long q = p.x; b) auto q = cast(long)p.x; Either way I've to specify the type "long" which I dislike (here it's not a real burdon, but with more complicated types it might be). Is there a way, to make q mutable without having to write the type explicitly?
Sep 05 2019
On Thursday, 5 September 2019 at 08:16:08 UTC, Daniel Kozak wrote:On Thu, Sep 5, 2019 at 9:55 AM berni via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:or: auto q = p.x + 0;I still struggle with the concept of immutable and const:in this case you can just use: auto q = cast()p.x;import std.stdio; void main() { auto p = Point(3); auto q = p.x; writeln(typeof(q).stringof); } struct Point { property immutable long x; }The type of q is immutable(long). But I need a mutable q. I found two ways: a) long q = p.x; b) auto q = cast(long)p.x; Either way I've to specify the type "long" which I dislike (here it's not a real burdon, but with more complicated types it might be). Is there a way, to make q mutable without having to write the type explicitly?
Sep 05 2019
On Thursday, 5 September 2019 at 08:16:08 UTC, Daniel Kozak wrote:in this case you can just use: auto q = cast()p.x;Ahh, great! :-) But that directly gets me to the next question:import std.stdio; void main() { Point[] q = [Point(1),Point(3),Point(2)]; import std.algorithm.searching: minElement; writeln(q.minElement!(a=>a.x).x); } struct Point { property immutable long x; }This doesn't compile:/usr/include/dmd/phobos/std/algorithm/searching.d(1365): Error: cannot modify struct extremeElement Point with immutable members /usr/include/dmd/phobos/std/algorithm/searching.d(1307): Error: template instance `test.main.extremum!(__lambda1, "a < b", Point[], Point)` error instantiating /usr/include/dmd/phobos/std/algorithm/searching.d(3445): instantiated from here: extremum!(__lambda1, "a < b", Point[]) test.d(8): instantiated from here: minElement!((a) => a.x, Point[])Any idea, how to get around this?
Sep 05 2019
On Thursday, 5 September 2019 at 08:44:35 UTC, berni wrote:This doesn't compile: [...] Any idea, how to get around this?Found the answer myself: q.map!(a=>a.x).minElement; :-)
Sep 05 2019
On Thursday, 5 September 2019 at 08:56:42 UTC, berni wrote:[..]And one more question:import std.algorithm: reverse; writeln(q.reverse);Here the compiler complains with:test.d(8): Error: template std.algorithm.mutation.reverse cannot deduce function from argument types !()(Point[]), candidates are: /usr/include/dmd/phobos/std/algorithm/mutation.d(2483): std.algorithm.mutation.reverse(Range)(Range r) if (isBidirectionalRange!Range && (hasSwappableElements!Range || hasAssignableElements!Range && hasLength!Range && isRandomAccessRange!Range || isNarrowString!Range && isAssignable!(ElementType!Range)))I allready tried to use q.dup.reverse but that didn't work either. How to get this working? (I hope I don't annoy you by asking that much questions, but I've got the feeling, that I've got only two choices: To shy away from using immutable (like I did in the last three years) or ask a lot of questions in the hope of understanding what's going on...
Sep 05 2019
On Thursday, 5 September 2019 at 09:07:30 UTC, berni wrote:https://dlang.org/library/std/range/retro.html Difference is, retro lazily iterates in reverse order, while reverse eagerly reverses in-place. Don't worry about asking questions - it's a good way to learn, and we like helping. :) Immutable is not very well supported everywhere in the library, sadly. It seems an important building block would be something like Reassignable!T, which would hold a struct with immutable members, and still be reassignable with different values. -- Simenimport std.algorithm: reverse; writeln(q.reverse);How to get this working? (I hope I don't annoy you by asking that much questions, but I've got the feeling, that I've got only two choices: To shy away from using immutable (like I did in the last three years) or ask a lot of questions in the hope of understanding what's going on...
Sep 05 2019
On Thursday, 5 September 2019 at 10:47:56 UTC, Simen Kjærås wrote:https://dlang.org/library/std/range/retro.htmlYeah, that worked. Thanks. :-)Don't worry about asking questionsOK. Then here's the next one:Point[long] q; q[1] = Point(3);Leads to:test.d(7): Error: cannot modify struct q[1L] Point with immutable members
Sep 05 2019
05.09.2019 14:17, berni пишет:But why do you try to modify immutable data? What is your point? Could you describe you use case?Point[long] q; q[1] = Point(3);Leads to:test.d(7): Error: cannot modify struct q[1L] Point with immutable members
Sep 05 2019
On Thursday, 5 September 2019 at 11:22:15 UTC, drug wrote:05.09.2019 14:17, berni пишет: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?But why do you try to modify immutable data? What is your point? Could you describe you use case?Point[long] q; q[1] = Point(3);Leads to:test.d(7): Error: cannot modify struct q[1L] Point with immutable members
Sep 05 2019
05.09.2019 14:28, berni пишет:On Thursday, 5 September 2019 at 11:22:15 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/rfKKAJ05.09.2019 14:17, berni пишет: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?But why do you try to modify immutable data? What is your point? Could you describe you use case?Point[long] q; q[1] = Point(3);Leads to:test.d(7): Error: cannot modify struct q[1L] Point with immutable members
Sep 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/rfKKAJOK. 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...
Sep 05 2019
05.09.2019 15:46, berni пишет:On Thursday, 5 September 2019 at 12:15:51 UTC, drug wrote: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_initializationOne solution could be using either pointer to `const(Point)` or class here (to avoid pointer using) https://run.dlang.io/is/rfKKAJOK. 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...
Sep 05 2019
On Thursday, 5 September 2019 at 13:27:55 UTC, drug wrote:[...]when you put it into an AA you modify old valueWhy?!? :-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_initializationWell, 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. :-(
Sep 05 2019
05.09.2019 17:31, berni пишет:On Thursday, 5 September 2019 at 13:27:55 UTC, drug wrote: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[...]when you put it into an AA you modify old valueWhy?!? :-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_initializationWell, 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. :-(
Sep 05 2019
On 09/05/2019 07:31 AM, berni wrote:On Thursday, 5 September 2019 at 13:27:55 UTC, drug 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 }[...]when you put it into an AA you modify old valueWhy?!? :-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.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
Sep 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...
Sep 05 2019
On 05.09.19 21:51, berni wrote:You're not putting an immutable int into an AA. You're copying the value of an immutable int to a mutable one.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. ?!?`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.
Sep 05 2019
On Thursday, 5 September 2019 at 20:10:03 UTC, ag0aep6g wrote:You're not putting an immutable int into an AA. You're copying the value of an immutable int to a mutable one.Ah, the point is not, that my object contains an immutable element, but that the base type of the AA is a type with an immutable element! I understand now. Thanks a lot!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.
Sep 06 2019
On 09/05/2019 12:51 PM, berni wrote:As explained elsewhere, a[1] is a mutable int. That assignment is copying b on top of the element.int[int] a; immutable int b = 17; a[1] = b; // <-- expecting error hereThat 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 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 hereOtherwise 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.const or immutable members make structs unassignable.But why? Here: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.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.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 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
Sep 05 2019
On Thursday, 5 September 2019 at 21:22:12 UTC, Ali Çehreli wrote: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.Got it. ;-)So, what I'm just trying all the time is not to have a struct with immutable elements but a immutable struct-object with mutable elements. I think, that's what I confused all the time.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.As a general rule, I never make members const or immutable; this is a guideline that I carried over from C++.I have almost no experience with C++, but I just accept that as a good advise. After all that discussion here, it seems to be sound. Thank you very much too! I think I made a big jump forward in understanding the concept of immutability in the last 24 hours. :-)
Sep 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.
Sep 06 2019
On Friday, 6 September 2019 at 08:47:07 UTC, Kagamin wrote: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.So it's more like a piece of paper, where there is place for a note. And when assigning, I erase that note (whatever it was) and write the new note at that place. Got it! :-)
Sep 06 2019