www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - how do I tell if something is lvalue?

reply Steven Schveighoffer <schveiguy yahoo.com> writes:
struct S
{
   int x;
   ref int y() { return x; }
   int z() { return 1; }
}

What can I use, given S, to determine that x and y yield lvalues, while 
z yields an rvalue?

I was expecting something like isLvalue somewhere, but cannot find it.

__traits(isRef, ...) doesn't work.

-Steve
Jan 31
parent reply Meta <jared771 gmail.com> writes:
On Sunday, 31 January 2016 at 20:49:43 UTC, Steven Schveighoffer 
wrote:
 struct S
 {
   int x;
   ref int y() { return x; }
   int z() { return 1; }
 }

 What can I use, given S, to determine that x and y yield 
 lvalues, while z yields an rvalue?

 I was expecting something like isLvalue somewhere, but cannot 
 find it.

 __traits(isRef, ...) doesn't work.

 -Steve
This seems to do the trick, although I haven't extensively tested it. There's probably a simpler way but this is the first thing I could come up with that works. template yieldsLval(Aggregate, alias member) { import std.traits: ReturnType; import std.functional: FunctionTypeOf; import std.typetuple: staticIndexOf; static if (isSomeFunction!member) { enum yieldsLval = __traits(compiles, { alias Ftype = FunctionTypeOf!member; void takesLval(ref ReturnType!Ftype) {} takesLval(Ftype()); }); } //It's a member variable else static if (staticIndexOf!(member.stringof, FieldNameTuple!Aggregate) > -1) enum yieldsLval = true; else static assert(false, "Symbol " ~ member.stringof ~ " is not a member function or variable of " ~ Aggregate.stringof); } struct S { int x; ref int y() { return x; } int z() { return 1; } enum f = 0; } void main() { static assert(yieldsLval!(S, S.y)); static assert(yieldsLval!(S, S.x)); static assert(!yieldsLval!(S, S.z)); static assert(!__traits(compiles, yieldsLval!(S, S.f))); }
Jan 31
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/31/16 4:48 PM, Meta wrote:

 This seems to do the trick, although I haven't extensively tested it.
 There's probably a simpler way but this is the first thing I could come
 up with that works.
Thanks! I was surprised this is not straightforward. -Steve
Jan 31
next sibling parent reply Meta <jared771 gmail.com> writes:
On Sunday, 31 January 2016 at 22:11:45 UTC, Steven Schveighoffer 
wrote:
 On 1/31/16 4:48 PM, Meta wrote:

 This seems to do the trick, although I haven't extensively 
 tested it.
 There's probably a simpler way but this is the first thing I 
 could come
 up with that works.
Thanks! I was surprised this is not straightforward. -Steve
It seems to me like it would be a useful addition to __traits.
Jan 31
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/31/16 5:12 PM, Meta wrote:
 On Sunday, 31 January 2016 at 22:11:45 UTC, Steven Schveighoffer wrote:
 On 1/31/16 4:48 PM, Meta wrote:

 This seems to do the trick, although I haven't extensively tested it.
 There's probably a simpler way but this is the first thing I could come
 up with that works.
Thanks! I was surprised this is not straightforward.
It seems to me like it would be a useful addition to __traits.
Yeah, the compiler probably has this handy. https://issues.dlang.org/show_bug.cgi?id=15634 -Steve
Feb 01
prev sibling next sibling parent reply Artur Skawina via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On 01/31/16 23:11, Steven Schveighoffer via Digitalmars-d-learn wrote:
 Thanks! I was surprised this is not straightforward.
enum isLvalue(alias A) = is(typeof((ref _){}(A))); artur
Feb 01
parent reply Meta <jared771 gmail.com> writes:
On Monday, 1 February 2016 at 18:28:05 UTC, Artur Skawina wrote:
 On 01/31/16 23:11, Steven Schveighoffer via Digitalmars-d-learn 
 wrote:
 Thanks! I was surprised this is not straightforward.
enum isLvalue(alias A) = is(typeof((ref _){}(A))); artur
That looks much nicer. It still needs work to properly handle functions with non-empty argument lists. Also, can alias parameters take runtime variables? I can't remember. struct S { int w(int n) { return 1; } } static assert(isLvalue!(S.w));
Feb 01
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 2/1/16 2:47 PM, Meta wrote:
 On Monday, 1 February 2016 at 18:28:05 UTC, Artur Skawina wrote:
 On 01/31/16 23:11, Steven Schveighoffer via Digitalmars-d-learn wrote:
 Thanks! I was surprised this is not straightforward.
enum isLvalue(alias A) = is(typeof((ref _){}(A))); artur
That looks much nicer. It still needs work to properly handle functions with non-empty argument lists. Also, can alias parameters take runtime variables? I can't remember. struct S { int w(int n) { return 1; } } static assert(isLvalue!(S.w));
Nice for the general case, but in my case, I don't need to worry about parameters. Thanks! -Steve
Feb 01
prev sibling next sibling parent Artur Skawina via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On 02/01/16 20:47, Meta via Digitalmars-d-learn wrote:
 On Monday, 1 February 2016 at 18:28:05 UTC, Artur Skawina wrote:
 On 01/31/16 23:11, Steven Schveighoffer via Digitalmars-d-learn wrote:
 Thanks! I was surprised this is not straightforward.
enum isLvalue(alias A) = is(typeof((ref _){}(A)));
That looks much nicer. It still needs work to properly handle functions with non-empty argument lists.
Then it gets a bit long for a one-liner ;) enum isLvalue(A...) = is(typeof((ref _){}(A[0](A[1..$])))) || is(typeof((ref _){}(A[0])));
 Also, can alias parameters take runtime variables? I can't remember.
Yes.
 
 struct S
 {
     int w(int n) { return 1; }
ref int wl(int n) { return x; }
 }
 
 static assert(isLvalue!(S.w));
static assert(!isLvalue!(S.w, 1)); static assert(isLvalue!(S.wl, 1)); artur
Feb 01
prev sibling parent reply Artur Skawina via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On 02/01/16 21:42, Artur Skawina wrote:
 On 02/01/16 20:47, Meta via Digitalmars-d-learn wrote:
 That looks much nicer. It still needs work to properly handle functions with
non-empty argument lists.
Then it gets a bit long for a one-liner ;) enum isLvalue(A...) = is(typeof((ref _){}(A[0](A[1..$])))) || is(typeof((ref _){}(A[0])));
And it's of course wrong in case there is a zero-args ref-returning overload present. So... enum isLvalue(A...) = A.length>1?is(typeof((ref _){}(A[0](A[1..$])))):is(typeof((ref _){}(A[0]))); artur
Feb 01
parent Meta <jared771 gmail.com> writes:
On Monday, 1 February 2016 at 20:53:35 UTC, Artur Skawina wrote:
 On 02/01/16 21:42, Artur Skawina wrote:
 On 02/01/16 20:47, Meta via Digitalmars-d-learn wrote:
 That looks much nicer. It still needs work to properly handle 
 functions with non-empty argument lists.
Then it gets a bit long for a one-liner ;) enum isLvalue(A...) = is(typeof((ref _){}(A[0](A[1..$])))) || is(typeof((ref _){}(A[0])));
And it's of course wrong in case there is a zero-args ref-returning overload present. So... enum isLvalue(A...) = A.length>1?is(typeof((ref _){}(A[0](A[1..$])))):is(typeof((ref _){}(A[0]))); artur
Hmm, I think it can be simplified by replacing `A[0](A[1..$])` with `A(Parameters!A.init)`. Then the whole thing becomes: enum isLvalue(alias A) = is(typeof((ref _) {} (A(Parameters!A.init)))); *However*, we then run into this problem: int n; ref int returnN(int, float, bool) { return n; } ref int returnN() { return n; } static assert(isLvalue!returnN); If I remember correctly this will just check the first returnN declaration.
Feb 01
prev sibling parent reply tsbockman <thomas.bockman gmail.com> writes:
On Sunday, 31 January 2016 at 22:11:45 UTC, Steven Schveighoffer 
wrote:
 Thanks! I was surprised this is not straightforward.

 -Steve
For function return values, at least, you can do this: import std.traits, std.stdio; int foo() { return 0; } ref int bar() { static int x = 0; return x; } enum isRetByRef(alias func) = (functionAttributes!func & FunctionAttribute.ref_) != 0; void main() { writeln("foo: ", isRetByRef!foo); writeln("bar: ", isRetByRef!bar); } (DPaste: http://dpaste.dzfl.pl/2aa8d3553a12)
Feb 01
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 2/1/16 5:20 PM, tsbockman wrote:
 On Sunday, 31 January 2016 at 22:11:45 UTC, Steven Schveighoffer wrote:
 Thanks! I was surprised this is not straightforward.

 -Steve
For function return values, at least, you can do this: import std.traits, std.stdio; int foo() { return 0; } ref int bar() { static int x = 0; return x; } enum isRetByRef(alias func) = (functionAttributes!func & FunctionAttribute.ref_) != 0; void main() { writeln("foo: ", isRetByRef!foo); writeln("bar: ", isRetByRef!bar); } (DPaste: http://dpaste.dzfl.pl/2aa8d3553a12)
Thanks. In my case, I need to treat fields and properties that return by ref the same way. What I wanted essentially was a template constraint that says "this type has a member named foo, and t.foo is an lvalue" -Steve
Feb 01
parent tsbockman <thomas.bockman gmail.com> writes:
On Monday, 1 February 2016 at 22:32:26 UTC, Steven Schveighoffer 
wrote:
 What I wanted essentially was a template constraint that says 
 "this type has a member named foo, and t.foo is an lvalue"

 -Steve
Like this? template hasLValProperty(T, string property) { enum hasLValProperty = __traits(compiles, function(ref T x) { void requireLVal(V)(ref V y) { } requireLVal(mixin("x." ~ property)); }); } struct Foo { int a; } struct Bar { int b() { return 0; } } struct Baz { ref int c() { static int _c; return _c; } } void test(T, string property)() { import std.stdio; write(T.stringof, ".", property, " is "); if(!hasLValProperty!(T, property)) write("NOT "); writeln("an lvalue"); } void main() { import std.stdio; test!(Foo, "a")(); test!(Foo, "b")(); test!(Bar, "a")(); test!(Bar, "b")(); test!(Baz, "c")(); } (DPaste: http://dpaste.dzfl.pl/5877cc17ffd2)
Feb 01
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/31/2016 01:48 PM, Meta wrote:

 This seems to do the trick, although I haven't extensively tested it.
There is hasLvalueElements() as well. Its implementation my be similar or give other ideas: https://dlang.org/phobos/std_range_primitives.html#hasLvalueElements Ali
Jan 31
parent Meta <jared771 gmail.com> writes:
On Monday, 1 February 2016 at 00:20:00 UTC, Ali Çehreli wrote:
 On 01/31/2016 01:48 PM, Meta wrote:

 This seems to do the trick, although I haven't extensively 
 tested it.
There is hasLvalueElements() as well. Its implementation my be similar or give other ideas: https://dlang.org/phobos/std_range_primitives.html#hasLvalueElements Ali
Unfortunately it's almost exactly the same as what I did, except for front, back, etc. Looks like there is currently no easier way.
Jan 31