digitalmars.D.learn - Does associative array change the location of values?
- Andrey Zherikov (5/5) Oct 29 2021 I want to have a pointer to a value in an associative array. Does
- Paul Backus (7/12) Oct 29 2021 No, the AA does not guarantee that the value will remain in the
- H. S. Teoh (7/21) Oct 29 2021 One way to achieve what the OP wants is to store a pointer to a
- Andrey Zherikov (2/9) Oct 29 2021 Thanks a lot for clarification
- Steven Schveighoffer (7/20) Oct 29 2021 This is incorrect, the buckets are each heap allocated. Just the array
- Stanislav Blinov (7/12) Oct 29 2021 Who's going to document these implementation details? ;) I mean,
- Imperatorn (3/18) Oct 29 2021 This should be documented for sure
- Andrey Zherikov (14/35) Oct 30 2021 I did small test and it printed the same values three times so
- Stanislav Blinov (7/11) Oct 30 2021 Address itself may change though. While the AA won't move stuff
- Imperatorn (3/15) Oct 30 2021 What test could be written to verify the behaviour?
- Stanislav Blinov (11/13) Oct 30 2021 Assuming the GC was moving?
- Elronnd (5/10) Oct 30 2021 If the GC were moving, it would also have to move the pointers
- Stanislav Blinov (2/5) Oct 30 2021 Who said you would?..
- =?UTF-8?Q?Ali_=c3=87ehreli?= (6/8) Oct 30 2021 I doubt D's GC can ever change pointer values because the values may be
- Elronnd (2/10) Oct 30 2021 Precise GC exists now.
- H. S. Teoh (6/15) Oct 31 2021 [...]
- =?UTF-8?Q?Ali_=c3=87ehreli?= (10/11) Oct 31 2021 Ok. :) What about unions?
- H. S. Teoh (7/19) Oct 31 2021 https://dlang.org/spec/garbage.html#obj_pinning_and_gc
- =?UTF-8?Q?Ali_=c3=87ehreli?= (4/6) Oct 31 2021 Ok, that was silly. There would be no reference to the GC memory if I=20
- Steven Schveighoffer (9/45) Oct 30 2021 Here is the rehash code, it definitely just moves around the buckets:
- Steven Schveighoffer (8/23) Oct 30 2021 It should be documented. There isn't a valid way to remove these
- Stanislav Blinov (7/13) Oct 30 2021 You won't introduce UB by deallocating unreferenced elements,
- Steven Schveighoffer (5/18) Oct 30 2021 auto v = k in aa;
- Stanislav Blinov (4/8) Oct 30 2021 ??? The same way it does for all other references.
- Steven Schveighoffer (11/22) Oct 30 2021 You said "deallocating unreferenced elements". I thought you meant
- Stanislav Blinov (4/13) Oct 30 2021 Yup, I misunderstood you :)
I want to have a pointer to a value in an associative array. Does AA guarantee that the value will remain at the same address all the time unless I remove the corresponding key? I couldn't find any guarantees similar to C++ iterator invalidation in D Language Reference.
Oct 29 2021
On Friday, 29 October 2021 at 17:40:38 UTC, Andrey Zherikov wrote:I want to have a pointer to a value in an associative array. Does AA guarantee that the value will remain at the same address all the time unless I remove the corresponding key? I couldn't find any guarantees similar to C++ iterator invalidation in D Language Reference.No, the AA does not guarantee that the value will remain in the same location. Inserting or removing *any* keys could cause the AA to resize, which may change the locations of all of its values. However, you do not have to worry about undefined behavior, because the garbage collector will keep the "stale" copy of the value alive as long as you hold a pointer to it.
Oct 29 2021
On Fri, Oct 29, 2021 at 05:58:24PM +0000, Paul Backus via Digitalmars-d-learn wrote:On Friday, 29 October 2021 at 17:40:38 UTC, Andrey Zherikov wrote:One way to achieve what the OP wants is to store a pointer to a heap-allocated object in the AA. Then AA rehashing won't change the value of the pointer. T -- Designer clothes: how to cover less by paying more.I want to have a pointer to a value in an associative array. Does AA guarantee that the value will remain at the same address all the time unless I remove the corresponding key? I couldn't find any guarantees similar to C++ iterator invalidation in D Language Reference.No, the AA does not guarantee that the value will remain in the same location. Inserting or removing *any* keys could cause the AA to resize, which may change the locations of all of its values. However, you do not have to worry about undefined behavior, because the garbage collector will keep the "stale" copy of the value alive as long as you hold a pointer to it.
Oct 29 2021
On Friday, 29 October 2021 at 17:58:24 UTC, Paul Backus wrote:No, the AA does not guarantee that the value will remain in the same location. Inserting or removing *any* keys could cause the AA to resize, which may change the locations of all of its values. However, you do not have to worry about undefined behavior, because the garbage collector will keep the "stale" copy of the value alive as long as you hold a pointer to it.Thanks a lot for clarification
Oct 29 2021
On 10/29/21 1:58 PM, Paul Backus wrote:On Friday, 29 October 2021 at 17:40:38 UTC, Andrey Zherikov wrote:This is incorrect, the buckets are each heap allocated. Just the array of bucket pointers would change. In addition, AAs do not deallocate the key/value pairs ever. You are safe to obtain a pointer to a value and it will stay there, even if you remove the key. -SteveI want to have a pointer to a value in an associative array. Does AA guarantee that the value will remain at the same address all the time unless I remove the corresponding key? I couldn't find any guarantees similar to C++ iterator invalidation in D Language Reference.No, the AA does not guarantee that the value will remain in the same location. Inserting or removing *any* keys could cause the AA to resize, which may change the locations of all of its values. However, you do not have to worry about undefined behavior, because the garbage collector will keep the "stale" copy of the value alive as long as you hold a pointer to it.
Oct 29 2021
On Friday, 29 October 2021 at 21:00:48 UTC, Steven Schveighoffer wrote:This is incorrect, the buckets are each heap allocated. Just the array of bucket pointers would change. In addition, AAs do not deallocate the key/value pairs ever. You are safe to obtain a pointer to a value and it will stay there, even if you remove the key.Who's going to document these implementation details? ;) I mean, if no one, then the above shouldn't be stated. Wouldn't you agree? Given the premise of the question at hand, it does seem useful to know these. But at least one should stress what is and isn't subject to change (even if unlikely).
Oct 29 2021
On Saturday, 30 October 2021 at 00:49:04 UTC, Stanislav Blinov wrote:On Friday, 29 October 2021 at 21:00:48 UTC, Steven Schveighoffer wrote:This should be documented for sureThis is incorrect, the buckets are each heap allocated. Just the array of bucket pointers would change. In addition, AAs do not deallocate the key/value pairs ever. You are safe to obtain a pointer to a value and it will stay there, even if you remove the key.Who's going to document these implementation details? ;) I mean, if no one, then the above shouldn't be stated. Wouldn't you agree? Given the premise of the question at hand, it does seem useful to know these. But at least one should stress what is and isn't subject to change (even if unlikely).
Oct 29 2021
On Saturday, 30 October 2021 at 00:52:23 UTC, Imperatorn wrote:On Saturday, 30 October 2021 at 00:49:04 UTC, Stanislav Blinov wrote:I did small test and it printed the same values three times so even rehash doesn't change the address of the value: ```d long[long] aa = [0:0]; writeln(&aa[0]); foreach(i; 0 .. 100_000_000) aa[i]=i; writeln(&aa[0]); aa.rehash; writeln(&aa[0]); ``` So it seems pretty safe to store a pointer to a value in AA. And I agree that this should definitely be documented.On Friday, 29 October 2021 at 21:00:48 UTC, Steven Schveighoffer wrote:This should be documented for sureThis is incorrect, the buckets are each heap allocated. Just the array of bucket pointers would change. In addition, AAs do not deallocate the key/value pairs ever. You are safe to obtain a pointer to a value and it will stay there, even if you remove the key.Who's going to document these implementation details? ;) I mean, if no one, then the above shouldn't be stated. Wouldn't you agree? Given the premise of the question at hand, it does seem useful to know these. But at least one should stress what is and isn't subject to change (even if unlikely).
Oct 30 2021
On Saturday, 30 October 2021 at 18:31:16 UTC, Andrey Zherikov wrote:I did small test and it printed the same values three times so even rehash doesn't change the address of the value:So it seems pretty safe to store a pointer to a value in AA. And I agree that this should definitely be documented.Address itself may change though. While the AA won't move stuff around, a GC might. I don't think current GC moves anything, but it's definitely allowed to. Which would be transparent to your code so long as you don't depend on the value of address itself :) https://dlang.org/spec/garbage.html#pointers_and_gc
Oct 30 2021
On Saturday, 30 October 2021 at 20:05:17 UTC, Stanislav Blinov wrote:On Saturday, 30 October 2021 at 18:31:16 UTC, Andrey Zherikov wrote:What test could be written to verify the behaviour?I did small test and it printed the same values three times so even rehash doesn't change the address of the value:So it seems pretty safe to store a pointer to a value in AA. And I agree that this should definitely be documented.Address itself may change though. While the AA won't move stuff around, a GC might. I don't think current GC moves anything, but it's definitely allowed to. Which would be transparent to your code so long as you don't depend on the value of address itself :) https://dlang.org/spec/garbage.html#pointers_and_gc
Oct 30 2021
On Saturday, 30 October 2021 at 20:19:58 UTC, Imperatorn wrote:Assuming the GC was moving? You'd need a loop allocating different sizes, storing the addresses somewhere the GC won't see (i.e. in memory allocated not with the GC: malloc, VirtualAlloc, mmap...), orphaning some allocations, repeating a bunch of times, and then comparing addresses of remaining allocations with stored ones. Behavior would very much depend on the GC implementation, so would a concrete test. Point is, it's allowed to move so we have to assume it would even if it doesn't, and relying on it not moving (i.e. depending on concrete addresses) is UB.https://dlang.org/spec/garbage.html#pointers_and_gcWhat test could be written to verify the behaviour?
Oct 30 2021
On Saturday, 30 October 2021 at 21:20:15 UTC, Stanislav Blinov wrote:On Saturday, 30 October 2021 at 20:19:58 UTC, Imperatorn wrote:If the GC were moving, it would also have to move the pointers you took to AA elements. You would never get stale pointers in any event.Assuming the GC was moving?https://dlang.org/spec/garbage.html#pointers_and_gcWhat test could be written to verify the behaviour?
Oct 30 2021
On Saturday, 30 October 2021 at 22:47:57 UTC, Elronnd wrote:If the GC were moving, it would also have to move the pointers you took to AA elements. You would never get stale pointers in any event.Who said you would?..
Oct 30 2021
On 10/30/21 3:47 PM, Elronnd wrote:If the GC were moving, it would also have to move the pointers you took to AA elements.I doubt D's GC can ever change pointer values because the values may be hiding inside e.g. ulong variables. And we would definitely not want the GC to change ulong values just because it thought they were familiar pointer values in disguise. :) Ali
Oct 30 2021
On Sunday, 31 October 2021 at 02:56:35 UTC, Ali Çehreli wrote:On 10/30/21 3:47 PM, Elronnd wrote:Precise GC exists now.If the GC were moving, it would also have to move thepointers you tookto AA elements.I doubt D's GC can ever change pointer values because the values may be hiding inside e.g. ulong variables. And we would definitely not want the GC to change ulong values just because it thought they were familiar pointer values in disguise. :)
Oct 30 2021
On Sat, Oct 30, 2021 at 07:56:35PM -0700, Ali Çehreli via Digitalmars-d-learn wrote:On 10/30/21 3:47 PM, Elronnd wrote:[...] The current spec explicitly states that masking pointers this way is UB. T -- Без труда не выловишь и рыбку из пруда.If the GC were moving, it would also have to move the pointers you took to AA elements.I doubt D's GC can ever change pointer values because the values may be hiding inside e.g. ulong variables. And we would definitely not want the GC to change ulong values just because it thought they were familiar pointer values in disguise. :)
Oct 31 2021
On 10/31/21 9:49 AM, H. S. Teoh wrote:The current spec explicitly states that masking pointers this way is UB.Ok. :) What about unions? union U { ulong u; void* p; } Can the GC deal with that? Or other smart ways where I store the pointer in two parts as page+offset? (Perhaps that's UB as well.) Ali
Oct 31 2021
On Sun, Oct 31, 2021 at 09:54:23AM -0700, Ali Çehreli via Digitalmars-d-learn wrote:On 10/31/21 9:49 AM, H. S. Teoh wrote:https://dlang.org/spec/garbage.html#obj_pinning_and_gc Though I have to say, object pinning does impose restrictions on a moving GC implementation that may negate some of its benefits. T -- Never criticize a man until you've walked a mile in his shoes. Then when you do criticize him, you'll be a mile away and he won't have his shoes.The current spec explicitly states that masking pointers this way is UB.Ok. :) What about unions? union U { ulong u; void* p; } Can the GC deal with that?
Oct 31 2021
On 10/31/21 9:54 AM, Ali =C3=87ehreli wrote:Or other smart ways where I store the pointer in two parts as=20 page+offset?Ok, that was silly. There would be no reference to the GC memory if I=20 chopped off a pointer. :/ Ali
Oct 31 2021
On 10/30/21 2:31 PM, Andrey Zherikov wrote:On Saturday, 30 October 2021 at 00:52:23 UTC, Imperatorn wrote:Here is the rehash code, it definitely just moves around the buckets: https://github.com/dlang/druntime/blob/20963f956c550b7b1b52849e5cf41f436d0df788/src/rt/aaA.d#L144-L157 That free at the end is just for the original `Bucket[]` array. A Bucket is just a hash and a void pointer to the actual key/value pair. When you get a pointer to an AA value, it's to the key/value pair block (there is no struct for this, it's done via runtime type information, which is horrific legacy). -SteveOn Saturday, 30 October 2021 at 00:49:04 UTC, Stanislav Blinov wrote:I did small test and it printed the same values three times so even rehash doesn't change the address of the value: ```d            long[long] aa = [0:0];            writeln(&aa[0]);            foreach(i; 0 .. 100_000_000)                    aa[i]=i;            writeln(&aa[0]);            aa.rehash;            writeln(&aa[0]); ``` So it seems pretty safe to store a pointer to a value in AA. And I agree that this should definitely be documented.On Friday, 29 October 2021 at 21:00:48 UTC, Steven Schveighoffer wrote:This should be documented for sureThis is incorrect, the buckets are each heap allocated. Just the array of bucket pointers would change. In addition, AAs do not deallocate the key/value pairs ever. You are safe to obtain a pointer to a value and it will stay there, even if you remove the key.Who's going to document these implementation details? ;) I mean, if no one, then the above shouldn't be stated. Wouldn't you agree? Given the premise of the question at hand, it does seem useful to know these. But at least one should stress what is and isn't subject to change (even if unlikely).
Oct 30 2021
On 10/29/21 8:49 PM, Stanislav Blinov wrote:On Friday, 29 October 2021 at 21:00:48 UTC, Steven Schveighoffer wrote:It should be documented. There isn't a valid way to remove these requirements, even if they are currently just an implementation detail -- code already depends on these properties. And D is a GC-based language, especially when using AAs. There is no reason to introduce undefined behavior for existing usage.This is incorrect, the buckets are each heap allocated. Just the array of bucket pointers would change. In addition, AAs do not deallocate the key/value pairs ever. You are safe to obtain a pointer to a value and it will stay there, even if you remove the key.Who's going to document these implementation details? ;) I mean, if no one, then the above shouldn't be stated. Wouldn't you agree?Given the premise of the question at hand, it does seem useful to know these. But at least one should stress what is and isn't subject to change (even if unlikely).The whole AA documentation probably needs some attention. -Steve
Oct 30 2021
On Saturday, 30 October 2021 at 11:59:15 UTC, Steven Schveighoffer wrote:It should be documented. There isn't a valid way to remove these requirements, even if they are currently just an implementation detail -- code already depends on these properties.And D is a GC-based language, especially when using AAs. There is no reason to introduce undefined behavior for existing usage.You won't introduce UB by deallocating unreferenced elements, which a given GC *may* be able to figure out. Therefore I object to "AAs do not deallocate the key/value pairs ever" part. Strongly :) Until such time that such a requirement is indeed set in stone, and not incidental.
Oct 30 2021
On 10/30/21 10:51 AM, Stanislav Blinov wrote:On Saturday, 30 October 2021 at 11:59:15 UTC, Steven Schveighoffer wrote:auto v = k in aa; aa.remove(k); How can the GC/compiler work out that there is still a reference? -SteveIt should be documented. There isn't a valid way to remove these requirements, even if they are currently just an implementation detail -- code already depends on these properties.And D is a GC-based language, especially when using AAs. There is no reason to introduce undefined behavior for existing usage.You won't introduce UB by deallocating unreferenced elements, which a given GC *may* be able to figure out. Therefore I object to "AAs do not deallocate the key/value pairs ever" part. Strongly :) Until such time that such a requirement is indeed set in stone, and not incidental.
Oct 30 2021
On Saturday, 30 October 2021 at 16:55:03 UTC, Steven Schveighoffer wrote:auto v = k in aa; aa.remove(k); How can the GC/compiler work out that there is still a reference???? The same way it does for all other references. I think either you misunderstood me, or I misunderstood you.
Oct 30 2021
On 10/30/21 1:38 PM, Stanislav Blinov wrote:On Saturday, 30 October 2021 at 16:55:03 UTC, Steven Schveighoffer wrote:You said "deallocating unreferenced elements". I thought you meant elements unreferenced by the AA. What I mean is, the AA isn't going to change implementations where it now deallocates values that may still have existing references. If that's the case, we can state that in the docs. e.g.: Removing a key does not deallocate the value that was removed. The value's lifetime is managed by the GC and will be alive until there are no references to that value. -Steveauto v = k in aa; aa.remove(k); How can the GC/compiler work out that there is still a reference???? The same way it does for all other references. I think either you misunderstood me, or I misunderstood you.
Oct 30 2021
On Saturday, 30 October 2021 at 17:45:57 UTC, Steven Schveighoffer wrote:You said "deallocating unreferenced elements". I thought you meant elements unreferenced by the AA.Yup, I misunderstood you :)What I mean is, the AA isn't going to change implementations where it now deallocates values that may still have existing references. If that's the case, we can state that in the docs. e.g.: Removing a key does not deallocate the value that was removed. The value's lifetime is managed by the GC and will be alive until there are no references to that value.:whateveritistodoathumbsuphere:
Oct 30 2021