digitalmars.D.learn - A proper WAT moment
- John Colvin (70/70) Oct 14 2019 Different ability to access a property depending if I'm inside
- Paul Backus (26/29) Oct 14 2019 You're attempting to call one of S's member functions without an
- John Colvin (4/34) Oct 15 2019 And all the other ones in my example that access members without
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (27/41) Oct 15 2019 Yeah, Paul's wrong here - the struct is what messes things up
- Paul Backus (29/39) Oct 15 2019 __traits(compiles) is lying to you again. If you replace it with
- Jacob Carlborg (30/34) Oct 16 2019 The thing is that it should be possible to access a non-static member
Different ability to access a property depending if I'm inside something else when I look? struct S { int a; static int b; int c() { return a; } static int d() { return 3; } int e() property { return a; } static int f() property { return 3; } } void foo(S s) { pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, s, "a"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, S, "a"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, s, "b"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, S, "b"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, s, "c"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, S, "c"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, s, "d"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, S, "d"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, s, "e"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, S, "e"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, s, "f"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, S, "f"))); } struct C(S) { void foo(S s) { pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, s, "a"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, S, "a"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, s, "b"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, S, "b"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, s, "c"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, S, "c"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, s, "d"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, S, "d"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, s, "e"))); // ALL True except for this one: pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, S, "e"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, s, "f"))); pragma(msg, __LINE__, " ", __traits(compiles, __traits(getMember, S, "f"))); } } alias C0 = C!S;
Oct 14 2019
On Monday, 14 October 2019 at 17:00:56 UTC, John Colvin wrote:Different ability to access a property depending if I'm inside something else when I look? [snip]You're attempting to call one of S's member functions without an instance of S to call it on. Reduced version: struct S { int a; int e() property { return a; } } void foo(S s) { pragma(msg, __LINE__, " ", __traits(compiles, S.e)); // true (???) S.e; // Error: need `this` for `e` of type ` property int()` } struct C { void foo(S s) { pragma(msg, __LINE__, " ", __traits(compiles, S.e)); // false S.e; // Error: `this` for `e` needs to be type `S` not type `C` } } The real issue here is that the first `__traits(compiles)` check succeeds, even though the actual expression fails.
Oct 14 2019
On Monday, 14 October 2019 at 19:45:11 UTC, Paul Backus wrote:On Monday, 14 October 2019 at 17:00:56 UTC, John Colvin wrote:And all the other ones in my example that access members without an instance that also compile? There's something pretty strange about the rules here.Different ability to access a property depending if I'm inside something else when I look? [snip]You're attempting to call one of S's member functions without an instance of S to call it on. Reduced version: struct S { int a; int e() property { return a; } } void foo(S s) { pragma(msg, __LINE__, " ", __traits(compiles, S.e)); // true (???) S.e; // Error: need `this` for `e` of type ` property int()` } struct C { void foo(S s) { pragma(msg, __LINE__, " ", __traits(compiles, S.e)); // false S.e; // Error: `this` for `e` needs to be type `S` not type `C` } } The real issue here is that the first `__traits(compiles)` check succeeds, even though the actual expression fails.
Oct 15 2019
On Tuesday, 15 October 2019 at 07:06:35 UTC, John Colvin wrote:On Monday, 14 October 2019 at 19:45:11 UTC, Paul Backus wrote:[snip]On Monday, 14 October 2019 at 17:00:56 UTC, John Colvin wrote:Different ability to access a property depending if I'm inside something else when I look? [snip]You're attempting to call one of S's member functions without an instance of S to call it on.Yeah, Paul's wrong here - the struct is what messes things up here, though I don't understand why. Just putting the first function inside a struct cause the exact same issue: struct S { int a; int e() property { return a; } } pragma(msg, __LINE__, " ", __traits(compiles,__traits(getMember, S, "e"))); void fun() { pragma(msg, __LINE__, " ", __traits(compiles,__traits(getMember, S, "e"))); } struct S2 { void fun() { pragma(msg, __LINE__, " ", __traits(compiles,__traits(getMember, S, "e"))); } } Interestingly, the code does of course actually compile: struct S3 { void fun() { alias a = __traits(getMember, S, "e"); } }The real issue here is that the first `__traits(compiles)` check succeeds, even though the actual expression fails.And all the other ones in my example that access members without an instance that also compile? There's something pretty strange about the rules here.
Oct 15 2019
On Tuesday, 15 October 2019 at 09:34:41 UTC, Simen Kjærås wrote:void fun() { pragma(msg, __LINE__, " ", __traits(compiles,__traits(getMember, S, "e"))); }__traits(compiles) is lying to you again. If you replace it with __traits(getMember, S, "e") ...you'll get an error.Interestingly, the code does of course actually compile: struct S3 { void fun() { alias a = __traits(getMember, S, "e"); } }I think this is the key. It compiles if you put it on the right-hand side of an alias declaration, but *not* if you write it as a bare expression: struct S3 { void fun() { __traits(getMember, S, "e"); // Error } } The difference is that in an alias declaration, __traits(getMember) isn't evaluated as a function call, whereas in a naked expression, it is. So the question becomes, why is __traits(getMember) evaluating property functions differently in different contexts? I suspect the answer has to do with the difference between the two error messages. In the context of a free function, it's "need `this` for `e`"--i.e., you're calling a member function without a receiver--so the compiler can infer that you didn't mean to call the function at all. In the context of a member function, however, it's "`this` needs to be type `S`, not `S2`"--i.e., you're (implicitly) calling a member function on the wrong type of receiver--so the compiler treats it the same as any other function call with incorrect arguments, and assumes you actually meant it. Of course, this is speculation; it would take looking at the compiler source to be sure.
Oct 15 2019
On 2019-10-15 09:06, John Colvin wrote:And all the other ones in my example that access members without an instance that also compile? There's something pretty strange about the rules here.The thing is that it should be possible to access a non-static member without an instance because it's possible to manually construct a delegate: class S { int a; int e() property { return a; } } void foo() { int function() f = &S.e; // this compiles int delegate() dg; S s; dg.ptr = &s; dg.funcptr = f; } struct C { void bar() { int function() f = &S.e; // this fails for some reason but should compile } } So the expression `S.e` should compile, because it can be part of a large expression, i.e. `&S.e`, which should compile. The strange thing is that it fails to compile inside `C`. But if `bar` is changed to a static method it compiles again. -- /Jacob Carlborg
Oct 16 2019