digitalmars.D.learn - AA and struct with const member
- frame (14/14) Dec 27 2021 I feel stupid right now: One cannot assign a struct that contains
- Era Scarecrow (59/73) Dec 27 2021 const/immutable members are to be set/assigned instantiation.
- Tejas (4/9) Dec 27 2021 The workaround is okay, but I think we should file a bug report
- frame (3/15) Dec 27 2021 I agree. I'll just wait if somebody can explain why this isn't a
- tsbockman (32/38) Dec 28 2021 [The spec
- frame (6/12) Dec 28 2021 This might be a typo in your example but why should it be a
- Stanislav Blinov (11/18) Dec 28 2021 Because opIndexAssign cannot distinguish at compile time between
- frame (5/15) Dec 28 2021 Of course but opIndexAssign() isn't there in my example. The
- Stanislav Blinov (10/27) Dec 28 2021 It is doing that. You've asked why that should be compile error,
- Era Scarecrow (20/30) Dec 29 2021 So i wonder if const and immutable would have different behaviors
- frame (3/6) Dec 27 2021 Of course casting the const away was the first thing I did but I
- Era Scarecrow (8/16) Dec 28 2021 Well the next step up would be if the key does exist, you could
- frame (4/8) Dec 28 2021 It's a matter of consistency - if a function returns something in
I feel stupid right now: One cannot assign a struct that contains const member to AA? Error: cannot modify struct instance ... of type ... because it contains `const` or `immutable` members This is considered a modification? ```d struct S { const(int) a; } S[string] test; test["a"] = S(1); ``` Whats the workaround for that?
Dec 27 2021
On Monday, 27 December 2021 at 19:38:38 UTC, frame wrote:I feel stupid right now: One cannot assign a struct that contains const member to AA? Error: cannot modify struct instance ... of type ... because it contains `const` or `immutable` members This is considered a modification? ```d struct S { const(int) a; } S[string] test; test["a"] = S(1); ``` Whats the workaround for that?const/immutable members are to be set/assigned instantiation. Most likely the problem is a bug and sounds like a) the struct doesn't exist in the AA, so it creates it (with a default) b) It tries to copy but contains a const and thus fails Passing a pointer will do you no good, since structs are likely to be on the stack. So let's try opAssign. ```d auto ref opAssign(S s) { this=s; return this; } ``` So we get ``` 'cannot modify struct instance `this` of type `S` because it contains `const` or `immutable` members'. ``` Alright let's look at the members we can work with. https://dlang.org/spec/hash-map.html I don't see an 'add' but i do see a 'require' which will add something in. So we try that. test.require("a", S(1)); ``` Now we get: Error: cannot modify struct instance `*p` of type `S` because it contains `const` or `immutable` members test.d(??): Error: template instance `object.require!(string, S)` error instantiating ``` Hmmm it really doesn't like it. Finally we can fake it. Let's make a mirror struct without the const, for the purposes of adding it. ```d struct S { const(int) a; } struct S2 { int a; } S[string] test; cast(S2[string])test = S2(1); ``` ``` Error: `cast(S2[string])test` is not an lvalue and cannot be modified ``` Well that's not going to work. Let's make it a pointer and allocate it instead. ```d S*[string] test; test["a"] = new S(1); ``` Success! So i summarize, either work with a pointer, or drop the const...
Dec 27 2021
On Tuesday, 28 December 2021 at 01:45:42 UTC, Era Scarecrow wrote:On Monday, 27 December 2021 at 19:38:38 UTC, frame wrote:The workaround is okay, but I think we should file a bug report for this. This is very ~~stupid~~ undesirable behaviour[...]const/immutable members are to be set/assigned instantiation. Most likely the problem is a bug and sounds like [...]
Dec 27 2021
On Tuesday, 28 December 2021 at 06:38:03 UTC, Tejas wrote:On Tuesday, 28 December 2021 at 01:45:42 UTC, Era Scarecrow wrote:I agree. I'll just wait if somebody can explain why this isn't a bug or wanted behaviour or a known issue.On Monday, 27 December 2021 at 19:38:38 UTC, frame wrote:The workaround is okay, but I think we should file a bug report for this. This is very ~~stupid~~ undesirable behaviour[...]const/immutable members are to be set/assigned instantiation. Most likely the problem is a bug and sounds like [...]
Dec 27 2021
On Tuesday, 28 December 2021 at 07:54:56 UTC, frame wrote:On Tuesday, 28 December 2021 at 06:38:03 UTC, Tejas wrote:[The spec says](https://dlang.org/spec/hash-map.html#construction_assignment_entries): ``` 2. If the assigned value type is equivalent with the AA element type: 1. If the indexing key does not yet exist in AA, a new AA entry will be allocated, and it will be initialized with the assigned value. 2. If the indexing key already exists in the AA, the setting runs normal assignment. ``` Thus, when the value type is constructable but not assignable: ```d struct S { const(int) a; } void test(S[string] aa, string key, int value) { // Should be a compile-time error, because it might reassign: test[key] = S(value); // Should be accepted, because they can be proven at compile time to never reassign: test.require("a", S(value)); test.update("a", () => S(value), (ref const(S)) => { }); } ``` `require` and `update` can be fixed rather easily in `object.d`; I have submitted [issue 22633](https://issues.dlang.org/show_bug.cgi?id=22633) with sample code.The workaround is okay, but I think we should file a bug report for this. This is very ~~stupid~~ undesirable behaviourI agree. I'll just wait if somebody can explain why this isn't a bug or wanted behaviour or a known issue.
Dec 28 2021
On Tuesday, 28 December 2021 at 10:02:13 UTC, tsbockman wrote:// Should be a compile-time error, because it might reassign: test[key] = S(value);This might be a typo in your example but why should it be a compile-time error, it cannot know if the key already exists in compile time on a variable. First time initialization should always work anyway.`require` and `update` can be fixed rather easily in `object.d`; I have submitted [issue 22633](https://issues.dlang.org/show_bug.cgi?id=22633) with sample code.Perfect. Thank you.
Dec 28 2021
On Tuesday, 28 December 2021 at 22:46:16 UTC, frame wrote:On Tuesday, 28 December 2021 at 10:02:13 UTC, tsbockman wrote:Because opIndexAssign cannot distinguish at compile time between initialization and assignment: ```d Stuff[Key] aa; aa[key] = Stuff(args); // ostensibly, initialization aa[key] = otherStuff; // assignment to existing value ``` Same syntax, different behavior. This can only be caught at runtime. `require` and `update` though should be able to pull this off, and that they don't is a bug.// Should be a compile-time error, because it might reassign: test[key] = S(value);This might be a typo in your example but why should it be a compile-time error, it cannot know if the key already exists in compile time on a variable. First time initialization should always work anyway.
Dec 28 2021
On Wednesday, 29 December 2021 at 01:11:13 UTC, Stanislav Blinov wrote:Because opIndexAssign cannot distinguish at compile time between initialization and assignment: ```d Stuff[Key] aa; aa[key] = Stuff(args); // ostensibly, initialization aa[key] = otherStuff; // assignment to existing value ``` Same syntax, different behavior. This can only be caught at runtime. `require` and `update` though should be able to pull this off, and that they don't is a bug.Of course but opIndexAssign() isn't there in my example. The compiler should call runtime's _aaGetY() or something like that directly.
Dec 28 2021
On Wednesday, 29 December 2021 at 02:33:08 UTC, frame wrote:On Wednesday, 29 December 2021 at 01:11:13 UTC, Stanislav Blinov wrote:It is doing that. You've asked why that should be compile error, and the answer is - because there's no way to distinguish between initialization and assignment here. I.e. you can't make one line compile and the other - not. Either both compile, or both don't. So if you allow them to compile, you'll have to have a runtime check, throwing an exception on attempt to assign. Which is just horrible. Better to leave the assignment a compile error, and make `require` and `update` do the job they're supposed to be doing.Because opIndexAssign cannot distinguish at compile time between initialization and assignment: ```d Stuff[Key] aa; aa[key] = Stuff(args); // ostensibly, initialization aa[key] = otherStuff; // assignment to existing value ``` Same syntax, different behavior. This can only be caught at runtime. `require` and `update` though should be able to pull this off, and that they don't is a bug.Of course but opIndexAssign() isn't there in my example. The compiler should call runtime's _aaGetY() or something like that directly.
Dec 28 2021
On Wednesday, 29 December 2021 at 01:11:13 UTC, Stanislav Blinov wrote:Because opIndexAssign cannot distinguish at compile time between initialization and assignment: ```d Stuff[Key] aa; aa[key] = Stuff(args); // ostensibly, initialization aa[key] = otherStuff; // assignment to existing value ``` Same syntax, different behavior. This can only be caught at runtime. `require` and `update` though should be able to pull this off, and that they don't is a bug.So i wonder if const and immutable would have different behaviors then. While you shouldn't be able to explicitly change a const item within a struct, replacing the whole struct i would think would be okay, on the basis that you're basically throwing whole old item away (*and may be equal to what you'd do with say swap*). Immutable on the other hand may want to refuse as it should basically have a lifetime of the array? Though if you can delete the item and then just add it in again it's a longer version of the same thing, just depends on if anything is using/referencing it or not. And casting away the constness is easy enough so maybe it won't be different. Though if it's a basic type it seems unlikely it would need a longer lifetime, and if it's a reference or array it already is separated from the struct and needs no such protection for the pointer. I don't know. I remember odd behavior with const/non-const stuff before.
Dec 29 2021
On Tuesday, 28 December 2021 at 01:45:42 UTC, Era Scarecrow wrote:Success! So i summarize, either work with a pointer, or drop the const...Of course casting the const away was the first thing I did but I think this is not very clean :D
Dec 27 2021
On Tuesday, 28 December 2021 at 07:51:04 UTC, frame wrote:On Tuesday, 28 December 2021 at 01:45:42 UTC, Era Scarecrow wrote:Well the next step up would be if the key does exist, you could then memcpy the result... which can have issues with non-native basic types. Probably better to make data private vs making it const. I tend to use const far more as input arguments to help denote it won't change references and less for elements in a struct. That or make it a class? I'm not sure.Success! So i summarize, either work with a pointer, or drop the const...Of course casting the const away was the first thing I did but I think this is not very clean :D
Dec 28 2021
On Tuesday, 28 December 2021 at 14:48:24 UTC, Era Scarecrow wrote:Probably better to make data private vs making it const. I tend to use const far more as input arguments to help denote it won't change references and less for elements in a struct. That or make it a class? I'm not sure.It's a matter of consistency - if a function returns something in const one should be able to store it without any type modification.
Dec 28 2021