www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Associative Array of Const Objects?

reply "bitwise" <bitwise.pvt gmail.com> writes:
class Test{}

void main()
{
	const(Test)[string] tests;
	tests["test"] = new Test();
}

This code used to work, but after upgrading to dmd 2.067, it no 
longer does.
--Error: cannot modify const expression tests["test"]

How do I insert an item into an associative array of const 
objects?
Mar 27 2015
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
bitwise:

 class Test{}

 void main()
 {
 	const(Test)[string] tests;
 	tests["test"] = new Test();
 }

 This code used to work, but after upgrading to dmd 2.067, it no 
 longer does.
 --Error: cannot modify const expression tests["test"]

 How do I insert an item into an associative array of const 
 objects?
You meant to say "associative array with const objects as values". I think the short answer is that you can't. This is a breaking change, I think, it broke some of my code too. But perhaps something like Rebindable could be used. Bye, bearophile
Mar 28 2015
parent "bitwise" <bitwise.pvt gmail.com> writes:
 perhaps something like Rebindable could be used.
Looking at Rebindable now, there is a useful example. There should probably be a mention of this on the const/immutable docs. For people coming from C++, this will not be obvious. auto a = Rebindable!(const Widget)(new Widget); a.y(); // fine a.x = 5; // error! can't modify const a a = new Widget; // fine Given the above example though, I have to say it's ridiculously verbose and I much prefer the C++ way. I have never used read-only-const in C++, nor would I, and it's really annoying that it's forced on D programmers. I can see the benefit of protecting the underlaying data, but not the pointer/reference itself. I'm assuming a DIP for this would be futile at best =/ Thanks
Mar 29 2015
prev sibling next sibling parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 27 March 2015 at 21:33:19 UTC, bitwise wrote:
 class Test{}

 void main()
 {
 	const(Test)[string] tests;
 	tests["test"] = new Test();
 }

 This code used to work, but after upgrading to dmd 2.067, it no 
 longer does.
 --Error: cannot modify const expression tests["test"]

 How do I insert an item into an associative array of const 
 objects?
FWIW, it was changed in https://github.com/D-Programming-Language/dmd/pull/4148 It seems Kenji argues that the first assignment (like in your case) should be allowed, because it's supposed to be a construction rather than an assignment, but I fail to see how the compiler could detect this in the general case.
Mar 28 2015
parent reply "bitwise" <bitwise.pvt gmail.com> writes:
I'm a little confused at this point why this doesn't work either:

const(Test) test = new Test();  // fine
test = new Test();                     // error


In C++, There is a clear distinction:

const Test *test1 = nullptr; // const before type
test1 = new Test();      // fine
	
Test *const test2 = nullptr; // const before identifier
test2 = new Test();      // error: test2 is readonly

Isn't there such a distinction in D?


I would have suggested that I got things backward, but this 
doesn't work either:

const Test test = new Test();
test = new Test(); // error: cannot modify const expression
Mar 29 2015
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
bitwise:

 I'm a little confused at this point why this doesn't work 
 either:
const and immutable are rather different between C++ and D, I suggest you to take a look at the documentation: http://dlang.org/const-faq.html Bye, bearophile
Mar 29 2015
prev sibling parent reply "anonymous" <anonymous example.com> writes:
On Sunday, 29 March 2015 at 18:43:32 UTC, bitwise wrote:
 I'm a little confused at this point why this doesn't work 
 either:

 const(Test) test = new Test();  // fine
 test = new Test();                     // error


 In C++, There is a clear distinction:

 const Test *test1 = nullptr; // const before type
 test1 = new Test();      // fine
 	
 Test *const test2 = nullptr; // const before identifier
 test2 = new Test();      // error: test2 is readonly

 Isn't there such a distinction in D?
Notice how you have that '*' there that allows you to distinguish the data from the reference. You can have a mutable pointer to const data in D, too: struct Test {} const(Test)* test1 = null; test1 = new Test; /* fine */ const(Test*) test2 = null; /* equivalent variant: const Test* test2 = null; */ test2 = new Test; /* Error: cannot modify const expression test2 */ You cannot have a mutable class object reference to const data, because syntactically that distinction isn't made in D. There is std.typecons.Rebindable, though: import std.typecons: Rebindable; class Test {} Rebindable!(const Test) test = null; test = new Test; /* fine */
 I would have suggested that I got things backward, but this 
 doesn't work either:

 const Test test = new Test();
 test = new Test(); // error: cannot modify const expression
`const Test test` is the same as `const(Test) test`.
Mar 29 2015
parent reply "bitwise" <bitwise.pvt gmail.com> writes:
On Sunday, 29 March 2015 at 19:04:30 UTC, anonymous wrote:
 Notice how you have that '*' there that allows you to 
 distinguish the data from the reference.

 You can have a mutable pointer to const data in D, too:

 struct Test {}
 const(Test)* test1 = null;
 test1 = new Test; /* fine */
 const(Test*) test2 = null;
 /* equivalent variant: const Test* test2 = null; */
 test2 = new Test; /* Error: cannot modify const expression 
 test2 */

 You cannot have a mutable class object reference to const data, 
 because syntactically that distinction isn't made in D. There 
 is std.typecons.Rebindable, though:

 import std.typecons: Rebindable;
 class Test {}
 Rebindable!(const Test) test = null;
 test = new Test; /* fine */

 I would have suggested that I got things backward, but this 
 doesn't work either:

 const Test test = new Test();
 test = new Test(); // error: cannot modify const expression
`const Test test` is the same as `const(Test) test`.
Interesting, but I still don't understand why D doesn't have something like this: const Test test; // or const(Test) test; test = new Test() // fine, underlaying data is const, the reference is not Test const test = new Test(); test.a = 5; // fine, test is read-only but underlaying data is not const test = new Test(); // error: test is read-only const(Test) const test = new Test(); test.a = 5; // error, underlaying data is const test = new Test(); // error: read-only
Mar 29 2015
next sibling parent "bitwise" <bitwise.pvt gmail.com> writes:
Although, I suppose this is still a step up from C# which has not 
const at all =O
Mar 29 2015
prev sibling parent reply "anonymous" <anonymous example.com> writes:
On Sunday, 29 March 2015 at 19:13:32 UTC, bitwise wrote:
 Interesting, but I still don't understand why D doesn't have 
 something like this:

 const Test test;    // or const(Test) test;
 test = new Test()  // fine, underlaying data is const, the 
 reference is not

 Test const test = new Test();
 test.a = 5;              // fine, test is read-only but 
 underlaying data is not const
 test = new Test();  // error: test is read-only

 const(Test) const test = new Test();
 test.a = 5;              // error, underlaying data is const
 test = new Test();  // error: read-only
I think the semantics you propose here are not good. The first example would change the meaning of existing syntax (bad). The second one shows a const reference to mutable data (head const), which is a no-go for D so far. Shuffling things around, this could be less disruptive addition to the language: Test const test; /* mutable reference to const data */ But: 1) Such placement based syntax is foreign to D. 2) It would be special syntax just for class types. 3) It's not how C++ rolls. `const Test test;` and `Test const test;` are equivalent in C++. You need that '*' in C++, too, to make a distinction between reference and data. 4) Rebindable works reasonably well, as far as I know. So there is not that much pressure to change the language.
Mar 29 2015
parent reply "bitwise" <bitwise.pvt gmail.com> writes:
 1) Such placement based syntax is foreign to D.
I would have to agree that this is a strange way to do things in any language. The great "int* a" vs "int *a" debate...
 2) It would be special syntax just for class types.
IMO, it would be worth it
 3) It's not how C++ rolls.
 `const Test test;` and `Test const test;` are equivalent in 
 C++. You need that '*' in C++, too, to make a distinction 
 between reference and data.
I'm a little confused. I was comparing a C++ pointer-to-class to a D reference, which are basically the same under the hood. I wasn't trying to bring up C++ value types. I'm not sure how they're relevant to the argument.
 4) Rebindable works reasonably well, as far as I know.
The verbosity and blatant disregard for DRY makes me CRY. See what I did there.. ;) Anyways, IMO, D could benefit from having "tailconst" but I think it's a moot point.
Mar 29 2015
next sibling parent "anonymous" <anonymous example.com> writes:
On Sunday, 29 March 2015 at 20:29:50 UTC, bitwise wrote:
 3) It's not how C++ rolls.
 `const Test test;` and `Test const test;` are equivalent in 
 C++. You need that '*' in C++, too, to make a distinction 
 between reference and data.
I'm a little confused. I was comparing a C++ pointer-to-class to a D reference, which are basically the same under the hood. I wasn't trying to bring up C++ value types. I'm not sure how they're relevant to the argument.
`Test` can be a pointer type: class C {}; typedef C *Test; const Test test1 = 0; Test const test2 = 0; /* same type as test1 */ The point is that C++ shares the problem: If all you have is one identifier (and no pointer star), you can't distinguish the data from the pointer. So C++ syntax could only be properly adopted into D, if D class references got something like the pointer star. At that point, current D syntax with parentheses would work, too.
 4) Rebindable works reasonably well, as far as I know.
The verbosity and blatant disregard for DRY makes me CRY. See what I did there.. ;) Anyways, IMO, D could benefit from having "tailconst" but I think it's a moot point.
Yeah, I don't like Rebindable very much either. But it works ok, so whatever. If you have strong arguments, maybe post to the general forum. For me it's just about aesthetics.
Mar 29 2015
prev sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
On Sun, 29 Mar 2015 20:29:49 +0000, bitwise wrote:

 The verbosity and blatant disregard for DRY makes me CRY.
 See what I did there.. ;)
you can always `alias` it to something funny or obscene.=
Mar 29 2015
prev sibling parent "Baz" <bb.temp gmx.com> writes:
On Friday, 27 March 2015 at 21:33:19 UTC, bitwise wrote:
 class Test{}

 void main()
 {
 	const(Test)[string] tests;
 	tests["test"] = new Test();
 }

 This code used to work, but after upgrading to dmd 2.067, it no 
 longer does.
 --Error: cannot modify const expression tests["test"]

 How do I insert an item into an associative array of const 
 objects?
Generally speaking, you can insert an item in a constructor: --- class Test{} const (Test)[string] tests; static this() { tests["test"] = new Test(); } class Bar { immutable (Test)[string] tests2; this() { this.tests2["test"] = new Test(); } } void main() { auto bar = new Bar; } --- The same problem already existed before 2.067 for AA with strings as value (string[string]), since they are immutable.
Mar 28 2015