www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Finding out ref-ness of the return of an auto ref function

reply Arafel <er.krali gmail.com> writes:
Hi all,

I'm hitting a problem that it's making crazy... is there any way to find 
out if the return of an `auto ref` function is actually ref or not?

So, according to the documentation [1] it depends on the return 
expressions... however in my case I'm implementing `opDispatch` in a 
wrapper type (and trying to carry over the ref-ness), so I don't know 
how can I check it.

Now, the whole point of this wrapper is to act differently based on 
whether the return is a reference or not (it already checks for 
`hasIndirections`, which btw doesn't help here either).

I've tried to use `__traits(isRef, ??? ) but I haven't been able to find 
out how to use it, it seems to be meant for parameters. Perhaps it would 
make sense to have something like `traits(isRef, return)`?

Also I have tried making two different overloads, with and without ref, 
but it didn't work either...

A.


[1]: https://dlang.org/spec/function.html#auto-ref-functions
Jun 12 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 12 June 2020 at 14:56:41 UTC, Arafel wrote:
 Hi all,

 I'm hitting a problem that it's making crazy... is there any 
 way to find out if the return of an `auto ref` function is 
 actually ref or not?

 So, according to the documentation [1] it depends on the return 
 expressions... however in my case I'm implementing `opDispatch` 
 in a wrapper type (and trying to carry over the ref-ness), so I 
 don't know how can I check it.

 Now, the whole point of this wrapper is to act differently 
 based on whether the return is a reference or not (it already 
 checks for `hasIndirections`, which btw doesn't help here 
 either).

 I've tried to use `__traits(isRef, ??? ) but I haven't been 
 able to find out how to use it, it seems to be meant for 
 parameters. Perhaps it would make sense to have something like 
 `traits(isRef, return)`?

 Also I have tried making two different overloads, with and 
 without ref, but it didn't work either...

 A.


 [1]: https://dlang.org/spec/function.html#auto-ref-functions
I think I have something that works: ref int foo(); int bar(); enum isLvalue(string expr) = q{ __traits(compiles, (auto ref x) { static assert(__traits(isRef, x)); }(} ~ expr ~ q{)) }; pragma(msg, mixin(isLvalue!"foo()")); // true pragma(msg, mixin(isLvalue!"bar()")); // false Basically, you can pass the result of the function call to a function with an `auto ref` parameter and check whether that parameter is inferred as ref or not.
Jun 12 2020
parent reply Arafel <er.krali gmail.com> writes:
On 12/6/20 18:15, Paul Backus wrote:
 
 I think I have something that works:
 
 ref int foo();
 int bar();
 
 enum isLvalue(string expr) = q{
      __traits(compiles, (auto ref x) {
          static assert(__traits(isRef, x));
      }(} ~ expr ~ q{))
 };
 
 pragma(msg, mixin(isLvalue!"foo()")); // true
 pragma(msg, mixin(isLvalue!"bar()")); // false
 
 Basically, you can pass the result of the function call to a function 
 with an `auto ref` parameter and check whether that parameter is 
 inferred as ref or not.
Thanks a lot! I have to say, it works, it's really, really clever... but it's also ugly as hell, and feels like a kludge. I had already tried something similar with an identity function, but I couldn't make it compile-time... I was missing the "compiles"+"static assert" trick. Also, it can become quite hard to check from within the function itself... in my case it's more or less doable because it's basically a forwarding, so I'm essentially doing a simple mixin, but in a more complex case (with perhaps even static ifs and whatever) I can see it becoming essentially unmanageable. All in all, I still think something like `__traits(isRef,return)` would still be worth adding! After all the compiler already has all the information, so it's just about exposing it. I'm trying to think of a library solution, but I find it very hard to express "the hypothetical result of calling the current function with the current parameters in the current context". A.
Jun 12 2020
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Friday, 12 June 2020 at 17:50:43 UTC, Arafel wrote:

 All in all, I still think something like 
 `__traits(isRef,return)` would still be worth adding! After all 
 the compiler already has all the information, so it's just 
 about exposing it. I'm trying to think of a library solution, 
 but I find it very hard to express "the hypothetical result of 
 calling the current function with the current parameters in the 
 current context".

 A.
If you're wrapping a function you can use a 'getFunctionAttributes' trait [1], which would contain a "ref" if that function returns ref. If, however, you're wrapping a function template, however, you won't know until you actually instantiate it, which is basically going back to Paul Backus' solution. So the compiler doesn't always have all the information :) [1] https://dlang.org/spec/traits.html#getFunctionAttributes
Jun 12 2020
parent reply Arafel <er.krali gmail.com> writes:
On 12/6/20 20:34, Stanislav Blinov wrote:
 On Friday, 12 June 2020 at 17:50:43 UTC, Arafel wrote:
 
 All in all, I still think something like `__traits(isRef,return)` 
 would still be worth adding! After all the compiler already has all 
 the information, so it's just about exposing it. I'm trying to think 
 of a library solution, but I find it very hard to express "the 
 hypothetical result of calling the current function with the current 
 parameters in the current context".

 A.
If you're wrapping a function you can use a 'getFunctionAttributes' trait [1], which would contain a "ref" if that function returns ref. If, however, you're wrapping a function template, however, you won't know until you actually instantiate it, which is basically going back to Paul Backus' solution. So the compiler doesn't always have all the information :) [1] https://dlang.org/spec/traits.html#getFunctionAttributes
Well, the compiler can know `typeof (return)`, so at that point and under the same circumstances it has know (and thus it could expose) the ref-ness. Also there could be a better and more straightforward way of checking if an expression would be an l-value... it seems it's not the first time it has appeared: https://issues.dlang.org/show_bug.cgi?id=15634 The forum thread linked in the bug report is also quite interesting.
Jun 13 2020
parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Saturday, 13 June 2020 at 09:13:36 UTC, Arafel wrote:

 If, however, you're wrapping a function template, however, you 
 won't know until you actually instantiate it, which is 
 basically going back to Paul Backus' solution. So the compiler 
 doesn't always have all the information :)
Well, the compiler can know `typeof (return)`, so at that point and under the same circumstances it has know (and thus it could expose) the ref-ness.
And it does, for functions, via the aforementioned trait. It can't for templates until those templates are instantiated, which you can only do correctly by actually forwarding arguments to it (because a function template may have auto ref parameters). Steven's issue report doesn't account for templates, nor overloading, and correctly testing the latter would pretty much require you to match argument types and ref-ness by hand anyway (yuck).
Jun 13 2020