digitalmars.D - Empty non-null Associative Arrays should be trivial or even the
- Rekel (11/11) Aug 03 2021 Having to insert dummy variables into an associative array in
- Mike Parker (21/31) Aug 03 2021 Associative arrays are initialized as empty by default. The
- Rekel (4/10) Aug 03 2021 Yes, you are absolutely correct. You've been faster at responding
- Rekel (43/43) Aug 03 2021 Feel free to disregard my previous post seems valid, as I seem to
- Mike Parker (22/25) Aug 03 2021 AAs have to do internal bookkeeping, with the buckets and such,
- Steven Schveighoffer (22/53) Aug 03 2021 An AA is really a struct with a pointer to an implementation struct.
Having to insert dummy variables into an associative array in order to initialize it (and prevent foreach loops from throwing a range violation error) seems very dirty to me. Why is there no syntax for empty initialization? Suddenly getting a nullpointer after removing a ~= in an entirely different part of my code is 1 (VERY problematic) thing, but I'm even more surprised by the possible 'fixes'. . . (which would be either a useless insertion & removal procedure or a nullpointer check I will never again need after initial steps.) Is there any plan of resolving this issue? I'm shocked this is even a thing at all.
Aug 03 2021
On Tuesday, 3 August 2021 at 15:51:43 UTC, Rekel wrote:Having to insert dummy variables into an associative array in order to initialize it (and prevent foreach loops from throwing a range violation error) seems very dirty to me. Why is there no syntax for empty initialization?Associative arrays are initialized as empty by default. The following compiles and prints nothing, as expected: ```d int[string] aa; foreach(k, v; aa) writeln(v); ``` What are you doing that causes the range violation?Suddenly getting a nullpointer after removing a ~= in an entirely different part of my code is 1 (VERY problematic) thing, but I'm even more surprised by the possible 'fixes'. . . (which would be either a useless insertion & removal procedure or a nullpointer check I will never again need after initial steps.)You mean, doing something like `aa["foo"]` gives you the range violation? That's intended. If the key was never assigned, it's just like trying to index a normal array with a value that's out of bounds. The proper way to check for an element in an AA is via `in`, which returns a pointer to the element if it exists and null if it doesn't: ```d int[string] aa; if(auto v = "foo" in aa) writeln(*v); else writeln("No foo."); ``` See: https://dlang.org/spec/hash-map.html#testing_membership
Aug 03 2021
On Tuesday, 3 August 2021 at 16:20:50 UTC, Mike Parker wrote:You mean, doing something like `aa["foo"]` gives you the range violation? That's intended. If the key was never assigned, it's just like trying to index a normal array with a value that's out of bounds. The proper way to check for an element in an AA is via `in`, which returns a pointer to the element if it exists and null if it doesn't:Yes, you are absolutely correct. You've been faster at responding than I have been at backtracking my previous statements, that is very impressive 😅, thanks for helping out.
Aug 03 2021
Feel free to disregard my previous post seems valid, as I seem to have misunderstood the meaning of AA's being null. (Wish I'd triple checked, it was an incorrect use of ) Sorry for wasting anyone's time... How can all properties still be callable with a null-AA? This surprises me. Also a small sidequestion; how come remove is part of AA's definition while the removal of items from dynamic lists is part of the library instead? --- https://tenor.com/view/justin-timberlake-jt-bad-teacher-stupid-ifeel-stupid-gif-3547095 For those interested, my range error was caused by the following mistake; ```d int[][int] aa; void addElement(int element) { aa[0] ~= element; } void main(string[] args) { // Works addElement(0); aa[0].writeln(); } void main(string[] args) { // Does not work aa[0].writeln(); } ``` Assumptions thus on present elements, although the first main does not allude to its absence. In particular, why can one `~=` when aa[0] does not exist? Likewise, why is this valid:? ```d int[] a; assert(a is null); // Strange to me this works as many have said dynamic arrays are structs. a ~= 1; writeln(a); writeln([] ~ 1); // But not writeln(null ~ 1); ``` --- Again sorry for my previous mistake. I'll be more careful in the future. - Paul
Aug 03 2021
On Tuesday, 3 August 2021 at 16:28:03 UTC, Rekel wrote:Also a small sidequestion; how come remove is part of AA's definition while the removal of items from dynamic lists is part of the library instead?AAs have to do internal bookkeeping, with the buckets and such, that dynamic arrays do not have to worry about. So they've had their own remove function from the beginning. As I recall, dynamic arrays didn't have a remove function back in the D1 days. Removal was a matter of iteration and slicing: ```d foreach(i, e; arr) { if(e == toRemove) { arr = a[0 .. i] ~ a[i+1 .. $]; break; } } ``` And the remove function we have now is not specifically for dynamic arrays. It's for ranges. Dynamic arrays happen to be ranges (courtesy of the range API implemented for them in std.array) so you can use them with that function and any function in std.algorithm. Static arrays and associative arrays are not ranges.
Aug 03 2021
On 8/3/21 12:28 PM, Rekel wrote:Feel free to disregard my previous post seems valid, as I seem to have misunderstood the meaning of AA's being null. (Wish I'd triple checked, it was an incorrect use of ) Sorry for wasting anyone's time... How can all properties still be callable with a null-AA? This surprises me.An AA is really a struct with a pointer to an implementation struct. Therefore, a null AA is still valid, it just has a null implementation (which is treated as an empty one). For example, AA length property looks like: ```d size_t aaLength(AA *impl) { if(impl is null) return 0; return impl.length; } ``` or something along those lines.Also a small sidequestion; how come remove is part of AA's definition while the removal of items from dynamic lists is part of the library instead?A remove of an AA is an amortized O(1) operation, which makes it fast enough to be a builtin property. Removal from a dynamic array involves shifting elements around, and is O(n), so it's left up to a library to do if it wishes.--- https://tenor.com/view/justin-timberlake-jt-bad-teacher-stupid-ifee -stupid-gif-3547095 For those interested, my range error was caused by the following mistake; ```d int[][int] aa; void addElement(int element) {     aa[0] ~= element; } void main(string[] args) { // Works     addElement(0);     aa[0].writeln(); } void main(string[] args) { // Does not work     aa[0].writeln(); } ```AA's have a special behavior depending on whether your indexed value is used as an rvalue or lvalue. So for instance `writeln(aa[0])` is using `aa[0]` as an rvalue, so no dummy element is inserted. However, `aa[0] ~= element` requires an lvalue, so one is added if it doesn't exist. -Steve
Aug 03 2021