Thread overview | ||||||||
---|---|---|---|---|---|---|---|---|
|
October 14, 2019 A proper WAT moment | ||||
---|---|---|---|---|
| ||||
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; |
October 14, 2019 Re: A proper WAT moment | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | 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.
|
October 15, 2019 Re: A proper WAT moment | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paul Backus | 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.
|
October 15, 2019 Re: A proper WAT moment | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | 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"); } } |
October 15, 2019 Re: A proper WAT moment | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | 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. |
October 16, 2019 Re: A proper WAT moment | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | 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 |
Copyright © 1999-2021 by the D Language Foundation