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









Stanislav Blinov <stanislav.blinov gmail.com> 