Thread overview
getSymbolsByUDA in constructor/member functions
Jun 15, 2022
cc
Jun 16, 2022
frame
Jun 16, 2022
Arafel
Jun 16, 2022
frame
Jun 16, 2022
Arafel
Jun 16, 2022
frame
Jun 16, 2022
Paul Backus
June 15, 2022
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, 2022

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, 2022
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, 2022

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, 2022
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, 2022

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, 2022

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