www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - A proper WAT moment

reply John Colvin <john.loughran.colvin gmail.com> writes:
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
parent reply Paul Backus <snarwin gmail.com> writes:
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
parent reply John Colvin <john.loughran.colvin gmail.com> writes:
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:
 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.
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
next sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
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:
 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.
[snip]
 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.
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"); } }
Oct 15 2019
parent Paul Backus <snarwin gmail.com> writes:
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
prev sibling parent Jacob Carlborg <doob me.com> writes:
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