digitalmars.D.learn - `this` template params for struct not expressing constness.
- adnan338 (34/34) Jun 08 2020 Hi, as far as I understand, the `this` template parameter
- evilrat (11/45) Jun 08 2020 If I correctly understand what you are trying to do the answer is
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (15/24) Jun 08 2020 This method is const, which means 'this' is const, while Self is
- adnan338 (6/30) Jun 08 2020 Thank you. Few followup questions, if you don't mind.
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (11/45) Jun 08 2020 Just forces the function to be a template. The only reason for
Hi, as far as I understand, the `this` template parameter includes constness qualifiers as seen in https://ddili.org/ders/d.en/templates_more.html To apply this I have this following struct: module bst; struct Tree(T) { T item; Tree!T* parent, left, right; this(T item) { this.item = item; } Self* searchTree(this Self)(auto in ref T item) const { if (&this is null) return null; if (this.item == item) return &this; return (this.item < item) ? this.right.searchTree(item) : this.right.searchTree(item); } } unittest { auto text1 = "Hello", text2 = "World"; auto tree2 = Tree!string(text1); assert(tree2.searchTree(text2) is null); assert(tree2.searchTree(text1) !is null); auto tree1 = Tree!int(4); assert(tree1.searchTree(5) is null); assert(tree1.searchTree(4) !is null); } When I run the unittest the compiler complains: cannot implicitly convert expression &this of type const(Tree!string)* to Tree!string* Run link: https://run.dlang.io/is/b76DND Why does this happen?
Jun 08 2020
On Monday, 8 June 2020 at 07:35:12 UTC, adnan338 wrote:Hi, as far as I understand, the `this` template parameter includes constness qualifiers as seen in https://ddili.org/ders/d.en/templates_more.html To apply this I have this following struct: module bst; struct Tree(T) { T item; Tree!T* parent, left, right; this(T item) { this.item = item; } Self* searchTree(this Self)(auto in ref T item) const { if (&this is null) return null; if (this.item == item) return &this; return (this.item < item) ? this.right.searchTree(item) : this.right.searchTree(item); } } unittest { auto text1 = "Hello", text2 = "World"; auto tree2 = Tree!string(text1); assert(tree2.searchTree(text2) is null); assert(tree2.searchTree(text1) !is null); auto tree1 = Tree!int(4); assert(tree1.searchTree(5) is null); assert(tree1.searchTree(4) !is null); } When I run the unittest the compiler complains: cannot implicitly convert expression &this of type const(Tree!string)* to Tree!string* Run link: https://run.dlang.io/is/b76DND Why does this happen?If I correctly understand what you are trying to do the answer is - in D const is transitive (unlike the C++ where it isn't). And in your searchTree() method you are basically trying to escape that constness. You can change the signature to return const(Self)*, or maybe add non-const overload depending on your needs. Don't even think about casting away const with `return cast(Self*) &this;` as this UB in D, and it will bite you somewhere later because compiler might rely on const for optimization.
Jun 08 2020
On Monday, 8 June 2020 at 07:35:12 UTC, adnan338 wrote:Self* searchTree(this Self)(auto in ref T item) const { if (&this is null) return null; if (this.item == item) return &this; return (this.item < item) ? this.right.searchTree(item) : this.right.searchTree(item); }This method is const, which means 'this' is const, while Self is not. What you're looking for here is inout (https://dlang.org/spec/function.html#inout-functions): auto searchTree()(auto in ref T item) inout { if (&this is null) return null; if (this.item == item) return &this; return (this.item < item) ? this.right.searchTree(item) : this.right.searchTree(item); } -- Simen
Jun 08 2020
On Monday, 8 June 2020 at 08:10:19 UTC, Simen Kjærås wrote:On Monday, 8 June 2020 at 07:35:12 UTC, adnan338 wrote:Thank you. Few followup questions, if you don't mind. 1. What does that blank template parameter mean? 2. Since `inout` acts as a wildcard for immutable/const/non-const qualifiers, what should I do to have the compiler ensure that my method does not mutate a non-const tree inside the body?Self* searchTree(this Self)(auto in ref T item) const { if (&this is null) return null; if (this.item == item) return &this; return (this.item < item) ? this.right.searchTree(item) : this.right.searchTree(item); }This method is const, which means 'this' is const, while Self is not. What you're looking for here is inout (https://dlang.org/spec/function.html#inout-functions): auto searchTree()(auto in ref T item) inout { if (&this is null) return null; if (this.item == item) return &this; return (this.item < item) ? this.right.searchTree(item) : this.right.searchTree(item); } -- Simen
Jun 08 2020
On Monday, 8 June 2020 at 09:08:40 UTC, adnan338 wrote:On Monday, 8 June 2020 at 08:10:19 UTC, Simen Kjærås wrote:Just forces the function to be a template. The only reason for this is it's required for auto ref to work, which you may or may not need on that function.On Monday, 8 June 2020 at 07:35:12 UTC, adnan338 wrote:Thank you. Few followup questions, if you don't mind. 1. What does that blank template parameter mean?Self* searchTree(this Self)(auto in ref T item) const { if (&this is null) return null; if (this.item == item) return &this; return (this.item < item) ? this.right.searchTree(item) : this.right.searchTree(item); }This method is const, which means 'this' is const, while Self is not. What you're looking for here is inout (https://dlang.org/spec/function.html#inout-functions): auto searchTree()(auto in ref T item) inout { if (&this is null) return null; if (this.item == item) return &this; return (this.item < item) ? this.right.searchTree(item) : this.right.searchTree(item); } -- Simen2. Since `inout` acts as a wildcard for immutable/const/non-const qualifiers, what should I do to have the compiler ensure that my method does not mutate a non-const tree inside the body?Inside inout functions, `this` is treated as const - any attempt to modify it should give a compile error. Since D const is transitive, anything reachable from `this` is also treated as const. If you're able to mutate a non-const tree inside the body, there's a bug in the compiler. -- Simen
Jun 08 2020