digitalmars.D.learn - ref struct member function
- PinDPlugga (36/36) May 13 2021 Hi I am working through Programming in D. In one exercise I have
- Steven Schveighoffer (8/19) May 13 2021 Just follow the recommendation:
- =?UTF-8?Q?Ali_=c3=87ehreli?= (41/65) May 13 2021 =20
- PinDPlugga (23/64) May 14 2021 Hi thank you both for your answers. I had understood from an
- ag0aep6g (10/36) May 14 2021 Note that opUnary is not an ordinary method. It's a template. That means...
- Paul Backus (17/21) May 14 2021 The error message here is definitely not as good as it could be.
Hi I am working through Programming in D. In one exercise I have a helper function in a struct ```D struct Fraction { auto n = 0L; auto d = 1L; // ... other bits ... ref Fraction reduce() { import std.numeric : gcd; v = gcd(n, d); if (v > 1) { n /= v; d /= v; } return this; } // ... etc ... } void main() { import std.stdio : writeln; auto f = Fraction(3, 9); writeln(f.reduce()); } ``` This works but issues a deprecation warning: ``` onlineapp.d(30): Deprecation: returning `this` escapes a reference to parameter `this` onlineapp.d(30): perhaps annotate the parameter with `return` Fraction(1, 3) ``` I found several other ways to make this work without the warnings, but I am wondering how to make this particular case work, or if it is not a recommended way, what the proper way would be.
May 13 2021
On 5/13/21 3:21 PM, PinDPlugga wrote:This works but issues a deprecation warning: ``` onlineapp.d(30): Deprecation: returning `this` escapes a reference to parameter `this` onlineapp.d(30): perhaps annotate the parameter with `return` Fraction(1, 3) ``` I found several other ways to make this work without the warnings, but I am wondering how to make this particular case work, or if it is not a recommended way, what the proper way would be.Just follow the recommendation: ```d ref Fraction reduce() return { // annotated with return ``` This means, "I will return all or part of the parameter passed in" (the parameter being the `this` reference) -Steve
May 13 2021
On 5/13/21 12:40 PM, Steven Schveighoffer wrote:On 5/13/21 3:21 PM, PinDPlugga wrote: =20This works but issues a deprecation warning: ``` onlineapp.d(30): Deprecation: returning `this` escapes a reference to =otate the parameter with `return`parameter `this` onlineapp.d(30):=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 perhaps ann==20Fraction(1, 3) ``` I found several other ways to make this work without the warnings, but=I am wondering how to make this particular case work, or if it is not ==20a recommended way, what the proper way would be.=20 Just follow the recommendation: =20 ```d ref Fraction reduce() return { // annotated with return ``` =20 This means, "I will return all or part of the parameter passed in" (the=parameter being the `this` reference) =20 -SteveI was writing this example that shows a use case for the problem (marked = with BUG below): struct Fraction { auto n =3D 0L; auto d =3D 1L; // ... other bits ... ref Fraction reduce() { import std.numeric : gcd; // v =3D gcd(n, d); // if (v > 1) { // n /=3D v; // d /=3D v; // } return this; } // ... etc ... } ref foo() { import std.stdio : writeln; auto f =3D Fraction(3, 9); // BUG: Returns reference to an object on the stack return f.reduce(); } void main() { // Refers to a temporary (it would be a copy without the &) auto f =3D &foo(); // Do some unrelated things hoping that space for dead objects on // the stack will be reused. import std.stdio; import std.random; writeln("doing something else: ", uniform(0, 6)); writeln(f.d); // Access dead and overwritten object (does NOT print // 9 on my system) } Putting 'return' where Steve shows makes the compiler guard us against=20 this misuse and the program thankfully does not compile. Ali
May 13 2021
On Thursday, 13 May 2021 at 19:48:44 UTC, Ali Çehreli wrote:I was writing this example that shows a use case for the problem (marked with BUG below): ```D struct Fraction { auto n = 0L; auto d = 1L; // ... other bits ... ref Fraction reduce() { import std.numeric : gcd; // v = gcd(n, d); // if (v > 1) { // n /= v; // d /= v; // } return this; } // ... etc ... } ref foo() { import std.stdio : writeln; auto f = Fraction(3, 9); // BUG: Returns reference to an object on the stack return f.reduce(); } void main() { // Refers to a temporary (it would be a copy without the &) auto f = &foo(); // Do some unrelated things hoping that space for dead objects on // the stack will be reused. import std.stdio; import std.random; writeln("doing something else: ", uniform(0, 6)); writeln(f.d); // Access dead and overwritten object (does NOT print // 9 on my system) } ``` Putting 'return' where Steve shows makes the compiler guard us against this misuse and the program thankfully does not compile. AliHi thank you both for your answers. I had understood from an earlier chapter how this could introduce a bug, but I was confused because the warning suggests attaching ```return``` to the parameter, which is empty in the declaration. So my next question would be how come ref based operator overloads are not labelled as return and do not show this warning? ``` D struct Fraction { auto n = 0L; auto d = 1L; ref Fraction opUnary(string op)() if (op == "++") { n += d; return this; } } ref Fraction foo() { auto f = Fraction(1, 3); // Same bug as with reduce return ++f; } ```
May 14 2021
On 14.05.21 12:00, PinDPlugga wrote:Hi thank you both for your answers. I had understood from an earlier chapter how this could introduce a bug, but I was confused because the warning suggests attaching ```return``` to the parameter, which is empty in the declaration.`this` is considered a hidden parameter. Every non-static method has it.So my next question would be how come ref based operator overloads are not labelled as return and do not show this warning? ``` D struct Fraction { auto n = 0L; auto d = 1L; ref Fraction opUnary(string op)() if (op == "++") { n += d; return this; } } ref Fraction foo() { auto f = Fraction(1, 3); // Same bug as with reduce return ++f; } ```Note that opUnary is not an ordinary method. It's a template. That means attributes are inferred [1], including the `return` attribute. I.e., the compiler adds `return` to the signature for you, just like Steven suggested you do manually. Try omitting the return type of `reduce` in your original code: ref reduce() { ... } That also enables attribute inference, and your code will compile. [1] https://dlang.org/spec/function.html#function-attribute-inference
May 14 2021
On Friday, 14 May 2021 at 10:00:28 UTC, PinDPlugga wrote:Hi thank you both for your answers. I had understood from an earlier chapter how this could introduce a bug, but I was confused because the warning suggests attaching ```return``` to the parameter, which is empty in the declaration.The error message here is definitely not as good as it could be. As a general rule, if you want to apply an attribute to the `this` reference in a member function, you write it after the parameter list: struct S { // ... auto memberFunc() const scope { // `this` is const and scope } auto anotherOne() share inout { // `this` is shared and inout } }
May 14 2021