digitalmars.D.learn - How to update Associative Array?
- tastyminerals (31/31) Feb 10 2022 Not sure if the `update` method got changed but I am having
- bauss (9/41) Feb 10 2022 You can just do:
- tastyminerals (4/15) Feb 10 2022 I meant a different thing though. I am looking for
- novice2 (4/7) Feb 10 2022 you need "merge"?
- =?UTF-8?Q?Ali_=c3=87ehreli?= (36/42) Feb 10 2022 Probably but Python's update updates the original dictionary. I came up
- kdevel (25/39) Feb 12 2022 It also looks scary to me and I use D now for quite a while.
- =?UTF-8?Q?Ali_=c3=87ehreli?= (35/73) Feb 12 2022 So, that code is not valid because a 'byte' cannot implicitly be
- kdevel (25/46) Feb 13 2022 It confuses me not really. (Function) templates are by their very
- =?UTF-8?Q?Ali_=c3=87ehreli?= (22/49) Feb 13 2022 Point taken but how deep should we understand library code, not all
- kdevel (5/18) Feb 18 2022 Interestingly
Not sure if the `update` method got changed but I am having trouble with understanding it now. I assumed it would work as easy as in Python:) Just do `mydic.update(dic)` or `mydic["key"].update(anotherDic)`. The docs have the following example. ``` class C{} C[string] aa; C older; C newer; aa.update("a", { newer = new C; return newer; }, (ref C c) { older = c; newer = new C; return newer; }); ``` This looks pretty scary and confusing to me tbo. Also, why is there an example with class and not simple `int[string]`? I just need to know how can I update let's say `int[string]` or nested `int[string][string]` AA. Should I also initialise and additional C classes before calling this method as in the example? Considering this is the only example in the docs I could find on how to update AA, imagine someone from Python world comes and sees this. Next thing he does, is close the page and never come back to D again :(
Feb 10 2022
On Thursday, 10 February 2022 at 10:59:17 UTC, tastyminerals wrote:Not sure if the `update` method got changed but I am having trouble with understanding it now. I assumed it would work as easy as in Python:) Just do `mydic.update(dic)` or `mydic["key"].update(anotherDic)`. The docs have the following example. ``` class C{} C[string] aa; C older; C newer; aa.update("a", { newer = new C; return newer; }, (ref C c) { older = c; newer = new C; return newer; }); ``` This looks pretty scary and confusing to me tbo. Also, why is there an example with class and not simple `int[string]`? I just need to know how can I update let's say `int[string]` or nested `int[string][string]` AA. Should I also initialise and additional C classes before calling this method as in the example? Considering this is the only example in the docs I could find on how to update AA, imagine someone from Python world comes and sees this. Next thing he does, is close the page and never come back to D again :(You can just do: aa[key] = value. If the key exist then it's updated, if it doesn't then it's added. The reason for the update function is simply in cases where you want to use the oldvalue etc. perhaps it has a timestamp that you need to keep etc. But in general you shouldn't need it.
Feb 10 2022
On Thursday, 10 February 2022 at 12:04:04 UTC, bauss wrote:On Thursday, 10 February 2022 at 10:59:17 UTC, tastyminerals wrote:I meant a different thing though. I am looking for `mydic.update(another_dic)` analogue where `{"a": 1, "b": 2}` update `{"c": 3, "a": -1}` becomes `{"a":-1, "b": 2, "c": 3}`.[...]You can just do: aa[key] = value. If the key exist then it's updated, if it doesn't then it's added. The reason for the update function is simply in cases where you want to use the oldvalue etc. perhaps it has a timestamp that you need to keep etc. But in general you shouldn't need it.
Feb 10 2022
On Thursday, 10 February 2022 at 12:08:07 UTC, tastyminerals wrote:I meant a different thing though. I am looking for `mydic.update(another_dic)` analogue where `{"a": 1, "b": 2}` update `{"c": 3, "a": -1}` becomes `{"a":-1, "b": 2, "c": 3}`.you need "merge"? https://forum.dlang.org/post/fhhuupczjnhehxpljxrj forum.dlang.org
Feb 10 2022
On 2/10/22 05:42, novice2 wrote:On Thursday, 10 February 2022 at 12:08:07 UTC, tastyminerals wrote:Probably but Python's update updates the original dictionary. I came up with the following function: import std.traits : isAssociativeArray, isImplicitlyConvertible, KeyType, ValueType; void update(Target, From)(ref Target target, From from) if (isAssociativeArray!Target && isAssociativeArray!From && isImplicitlyConvertible!(KeyType!From, KeyType!Target) && isImplicitlyConvertible!(ValueType!From, ValueType!Target)) { foreach (kv; from.byKeyValue) { target[kv.key] = kv.value; } } unittest { auto a = [ "a": 1, "b": 2 ]; a.update([ "c": 3, "a": -1 ]); assert(a == [ "a": -1, "b": 2, "c": 3 ]); } void main() { } Yes, it may look scary to newcomers to D but the template constraint is just for improved usability. (Still, I suspect it's not complete.) Otherwise, the following is the same thing: void update(Target, From)(ref Target target, From from) { foreach (kv; from.byKeyValue) { target[kv.key] = kv.value; } } 'ref' is needed there to work with null AAs. Without 'ref', the following would not work: int[string] aa; aa.update([ "x" : 42 ]); 'aa' would be null! Welcome to AA reference semantics. :) AliI meant a different thing though. I am looking for `mydic.update(another_dic)` analogue where `{"a": 1, "b": 2}` update `{"c": 3, "a": -1}` becomes `{"a":-1, "b": 2, "c": 3}`.you need "merge"? https://forum.dlang.org/post/fhhuupczjnhehxpljxrj forum.dlang.org
Feb 10 2022
On Thursday, 10 February 2022 at 17:09:23 UTC, Ali Çehreli wrote:import std.traits : isAssociativeArray, isImplicitlyConvertible, KeyType, ValueType; void update(Target, From)(ref Target target, From from) if (isAssociativeArray!Target && isAssociativeArray!From && isImplicitlyConvertible!(KeyType!From, KeyType!Target) && isImplicitlyConvertible!(ValueType!From, ValueType!Target)) { foreach (kv; from.byKeyValue) { target[kv.key] = kv.value; } }[...]Yes, it may look scary to newcomers to D but the template constraint is just for improved usability.It also looks scary to me and I use D now for quite a while. Assume I have this client code: string[int] q; byte[short] r; q.update (r); It produces this error message from your version: $ dmd -checkaction=context -unittest -run v1 v1.d(21): Error: template `v1.update` cannot deduce function from argument types `!()(string[int], byte[short])` v1.d(3): Candidate is: `update(Target, From)(ref Target target, From from)` with `Target = string[int], From = byte[short]` must satisfy the following constraint: ` isImplicitlyConvertible!(ValueType!From, ValueType!Target)` If I remove the constraint (the if-stuff) I get v1.d(12): Error: cannot implicitly convert expression `kv.value()` of type `byte` to `string` v1.d(23): Error: template instance `v1.update!(string[int], byte[short])` error instantiating Can this really be improved? Stefan
Feb 12 2022
On 2/12/22 13:37, kdevel wrote:On Thursday, 10 February 2022 at 17:09:23 UTC, Ali Çehreli wrote:So, that code is not valid because a 'byte' cannot implicitly be converted to a 'string'.import std.traits : isAssociativeArray, isImplicitlyConvertible, KeyType, ValueType; void update(Target, From)(ref Target target, From from) if (isAssociativeArray!Target && isAssociativeArray!From && isImplicitlyConvertible!(KeyType!From, KeyType!Target) && isImplicitlyConvertible!(ValueType!From, ValueType!Target)) { foreach (kv; from.byKeyValue) { target[kv.key] = kv.value; } }[...]Yes, it may look scary to newcomers to D but the template constraint is just for improved usability.It also looks scary to me and I use D now for quite a while. Assume I have this client code: string[int] q; byte[short] r; q.update (r);It produces this error message from your version: $ dmd -checkaction=context -unittest -run v1 v1.d(21): Error: template `v1.update` cannot deduce function from argument types `!()(string[int], byte[short])` v1.d(3): Candidate is: `update(Target, From)(ref Target target, From from)` with `Target = string[int], From = byte[short]` must satisfy the following constraint: ` isImplicitlyConvertible!(ValueType!From, ValueType!Target)`That looks like a wall of text but is much better than before. Now, the compiler is telling us what requirement could not be met. Additionally, the compilation fail in user code; telling the user why their code is not valid.If I remove the constraint (the if-stuff) I get v1.d(12): Error: cannot implicitly convert expression `kv.value()` of type `byte` to `string` v1.d(23): Error: template instance `v1.update!(string[int], byte[short])` error instantiatingThat's inferior because now the error message is pointing at the implementation of a library function and confuses everyone. We have such functions in Phobos.Can this really be improved?I am not sure. Here is an idea, which doesn't seem to add much as is: 'if' constraints could have a message for an improved error message like "This function template could not be used because 'byte' cannot implicitly be converted to 'string'." Note that there could be many candidates like "And this function template could not be used because 42 is not prime", etc. The programmer would read all those and figure out usable parameters. But I think those would just be translations of the error messages. Another idea is perhaps the compiler could resolve ValueType!From to 'byte' and provide the more readable isImplicitlyConvertible!(byte, string) I don't know how feasible that is. Still, I am glad the error messages today are much better. After all, everything that the programmer needs is spelled out here. It requires following some types: with `Target = string[int], From = byte[short]` must satisfy the following constraint: isImplicitlyConvertible!(ValueType!From, ValueType!Target)` The only thing that's not readily available there is ValueType but at least it's very readable. Sorry, I rambled but I'm under the impression that this complexity is inherent. Ali
Feb 12 2022
On Sunday, 13 February 2022 at 01:27:45 UTC, Ali Çehreli wrote:[...]It confuses me not really. (Function) templates are by their very nature visible to the user and I got used to reading the implementations. Nonetheless may the compiler-generated checks be moved into the interface: void update(Target, From)(ref Target target, From from, Target dummy = From.init) For this function template dmd reports in case of incompatible types: cannot implicitly convert expression `null` of type `byte[short]` to `string[int]`If I remove the constraint (the if-stuff) I get v1.d(12): Error: cannot implicitly convert expression`kv.value()`of type `byte` to `string` v1.d(23): Error: template instance`v1.update!(string[int],byte[short])` error instantiatingThat's inferior because now the error message is pointing at the implementation of a library function and confuses everyone.[...]After all, everything that the programmer needs is spelled out here. It requires following some types: with `Target = string[int], From = byte[short]` must satisfy the following constraint: isImplicitlyConvertible!(ValueType!From, ValueType!Target)` The only thing that's not readily available there is ValueType but at least it's very readable.The constraints appear artificial to me: Neither are there means which ensure that a list of Constraints is complete nor is it ensured that a list of constraints is not overly restrictive. It seems that these Constraints constitute another class of things which may get out of sync with the actual code (besides program documentation, program comments and function names). Doesn't this re-iteration of what is already implicitly contained in the line target[kv.key] = kv.value; violate the DRY principle?
Feb 13 2022
On 2/13/22 05:58, kdevel wrote:On Sunday, 13 February 2022 at 01:27:45 UTC, Ali Çehreli wrote:Point taken but how deep should we understand library code, not all being Phobos. My pet peeve: import std.stdio; void main(string[] args) { writefln!"hello"(42); } /usr/include/dlang/dmd/std/stdio.d(4442): Error: no property `msg` for type `string` I am happy that it's caught at compile time but what 'msg' property are we talking about? What does it have to be with me? I would like it if the It would be better if the compilation error said: Must satify formatSpecsMatchArgs!("hello", int) I am not sure whether it's practical or efficient at compile time.[...]It confuses me not really. (Function) templates are by their very nature visible to the user and I got used to reading the implementations.If I remove the constraint (the if-stuff) I get v1.d(12): Error: cannot implicitly convert expression`kv.value()`of type `byte` to `string` v1.d(23): Error: template instance`v1.update!(string[int],byte[short])` error instantiatingThat's inferior because now the error message is pointing at the implementation of a library function and confuses everyone.The constraints appear artificial to me: Neither are there means which ensure that a list of Constraints is complete nor is it ensured that a list of constraints is not overly restrictive.Agreed.It seems that these Constraints constitute another class of things which may get out of sync with the actual code (besides program documentation, program comments and function names).Agreed.Doesn't this re-iteration of what is already implicitly contained in the line target[kv.key] = kv.value;I don't agree with that because there is no 'target', 'kv', etc. in the programmer's code. Should we really expect the programmers be programmers? :pviolate the DRY principle?Agreed. Ali
Feb 13 2022
On Monday, 14 February 2022 at 01:04:08 UTC, Ali Çehreli wrote: [...]Point taken but how deep should we understand library code, not all being Phobos. My pet peeve: import std.stdio; void main(string[] args) { writefln!"hello"(42); } /usr/include/dlang/dmd/std/stdio.d(4442): Error: no property `msg` for type `string` I am happy that it's caught at compile time but what 'msg' property are we talking about? What does it have to be with me? I would like it if the It would be better if the compilation error said: Must satify formatSpecsMatchArgs!("hello", int)Interestingly writefln ("hello", 42); does not throw at runtime.
Feb 18 2022