Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
June 08, 2020 `this` template params for struct not expressing constness. | ||||
---|---|---|---|---|
| ||||
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? |
June 08, 2020 Re: `this` template params for struct not expressing constness. | ||||
---|---|---|---|---|
| ||||
Posted in reply to adnan338 | 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.
|
June 08, 2020 Re: `this` template params for struct not expressing constness. | ||||
---|---|---|---|---|
| ||||
Posted in reply to adnan338 | 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 |
June 08, 2020 Re: `this` template params for struct not expressing constness. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | 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:
>> 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
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?
|
June 08, 2020 Re: `this` template params for struct not expressing constness. | ||||
---|---|---|---|---|
| ||||
Posted in reply to adnan338 | 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: >> 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 > > Thank you. Few followup questions, if you don't mind. > > 1. What does that blank template parameter mean? 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. > 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? 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 |
Copyright © 1999-2021 by the D Language Foundation