Thread overview
getSymbolsByUDA in constructor/member functions
Jun 15
cc
Jun 16
frame
Jun 16
Arafel
Jun 16
frame
Jun 16
Arafel
Jun 16
frame
June 15
import std.traits;
class XML {}

class Def {
	@XML {
		int x;
		int y;
	}
	int z;

	this() {
		static foreach (sym; getSymbolsByUDA!(Def, XML)) {
		}
	}
}

void main() {
	auto def = new Def;
}
test.d(12): Error: value of `this` is not known at compile time
test.d(12): Error: value of `this` is not known at compile time

Why doesn't this work? There is nothing in the foreach body.

alias ALL = getSymbolsByUDA!(Def, XML);
pragma(msg, ALL.stringof);

reports tuple(this.x, this.y). Why is this. added?

June 16

On Wednesday, 15 June 2022 at 12:26:40 UTC, cc wrote:

>

Why doesn't this work? There is nothing in the foreach body.

alias ALL = getSymbolsByUDA!(Def, XML);
pragma(msg, ALL.stringof);

reports tuple(this.x, this.y). Why is this. added?

I can only answer this partially, I guess this is just added because getSymbolsByUDA want an instance but @XML is only seen as a type. As instance, you need to write @XML() instead:

class XML {
    static opCall() {
        return new XML();
    }
}

class Def {
	@XML() {
		int x;
		int y;
	}
	int z;

	this() {
		static foreach (sym; getSymbolsByUDA!(Def, XML)) {
		}
	}
}
June 16
On 15/6/22 14:26, cc wrote:
> ```d
> import std.traits;
> class XML {}
> 
> class Def {
>      @XML {
>          int x;
>          int y;
>      }
>      int z;
> 
>      this() {
>          static foreach (sym; getSymbolsByUDA!(Def, XML)) {
>          }
>      }
> }
> 
> void main() {
>      auto def = new Def;
> }
> ```
> ```
> test.d(12): Error: value of `this` is not known at compile time
> test.d(12): Error: value of `this` is not known at compile time
> ```
> 
> Why doesn't this work?  There is nothing in the foreach body.
> 
> ```d
> alias ALL = getSymbolsByUDA!(Def, XML);
> pragma(msg, ALL.stringof);
> ```
> reports `tuple(this.x, this.y)`.  Why is `this.` added?


I think it's a bug either in the `getSymbolsByUDA` implementation, or actually rather in the `__traits` system.

A workaround bypassing `getSymbolsByUDA`:

```d
import std.traits;
import std.meta: Alias;

class XML {}

class Def {
    @XML {
        int x;
    	int y;
    }
    int z;

    this() {
        static foreach (sym; __traits(allMembers, Def)) {{
            alias member = Alias!(__traits(getMember, Def, sym));
            static if (hasUDA!(member, XML)) {
                pragma(msg, member.stringof);
                pragma(msg, sym);
            }
        }}
    }
}

void main() {
    auto def = new Def;
}
```

As you can see, it's `getMember` who is returning a reference to the `this` instance. In my view, this is a bug according the documentation and examples [1]. It might be that classes behave differently, but then it should be documented.

In fact, it shouldn't work at all and you'd need to instantiate Def: `getMember` should fail because `x` and `y` are not static.

Interestingly, `hasUDA` (or rather `__traits(getAttributes, ...)`) later doesn't care about the dangling `this` reference, so I'm not sure who is to blame here... in any case, at the very least the documentation doesn't match the actual behavior.

[1]: https://dlang.org/spec/traits.html#getMember
June 16

On Thursday, 16 June 2022 at 08:23:20 UTC, Arafel wrote:

>

As you can see, it's getMember who is returning a reference to the this instance. In my view, this is a bug according the documentation and examples [1]. It might be that classes behave differently, but then it should be documented.

>

In fact, it shouldn't work at all and you'd need to instantiate Def: getMember should fail because x and y are not static.

This is not true. getMember can return the symbol to the instance or the type/alias, depending if you pass this or Def. The last is static.

It makes no sense to use the attribute from a class without an instance.

June 16
On 16/6/22 10:55, frame wrote:
> On Thursday, 16 June 2022 at 08:23:20 UTC, Arafel wrote:
> 
> 
> This is not true. `getMember` can return the symbol to the instance or the type/alias, depending if you pass `this` or `Def`. The last is static.
> 
> It makes no sense to use the attribute from a class without an instance.
> 
> 

Classes can have static members just as structs, so I don't think you always need an instance for a class either.

It seems the issue could be somewhere else:

```
import std.traits: getSymbolsByUDA;

enum E;

class C {
    @E int a;
    pragma(msg, __traits(getMember,C,"a").stringof); // `a`
    void foo() {
        pragma(msg, C.stringof); // `C`
        pragma(msg, __traits(getMember,C,"a").stringof); // `this.C.a`
        // Fails here
        //static foreach (sym; getSymbolsByUDA!(C, E)) { }
    }
    // But works here
    static foreach (sym; getSymbolsByUDA!(C, E)) { }
}

```

So if you call `getMember` from a member function, it adds the hidden `this` reference, and this has subtle consequences later on, even if `this.C` is practically just an alias for `C`.

I still think this is a bug in `getMember`, although perhaps not as obvious as I first thought.
June 16

On Thursday, 16 June 2022 at 09:29:36 UTC, Arafel wrote:

>

Classes can have static members just as structs, so I don't think you always need an instance for a class either.

Well, ok.

>

So if you call getMember from a member function, it adds the hidden this reference, and this has subtle consequences later on, even if this.C is practically just an alias for C.

I still think this is a bug in getMember, although perhaps not as obvious as I first thought.

Maybe you are right. I also don't see why the this reference should be there in the static call.

But it looks like a compiler bug since the output of getSymbolsByUDA is just an alias sequence and nothing should happen before consuming it?

This works fine too:

class C
{
    @E int a;

    void foo()
    {
        alias seq = getSymbolsByUDA!(C, E);
        static foreach (i; 0 .. seq.length)
        {
            pragma(msg, hasUDA!(seq[i], E));
        }
    }
}
June 16

On Thursday, 16 June 2022 at 13:27:25 UTC, frame wrote:

>

But it looks like a compiler bug since the output of getSymbolsByUDA is just an alias sequence and nothing should happen before consuming it?

Yes, this is a compiler bug. I've filed a report for it on bugzilla:

https://issues.dlang.org/show_bug.cgi?id=23192