On Monday, 22 August 2022 at 14:42:10 UTC, Andrey Zherikov wrote:
My situation is that user can write some UDA expression and I'm
checking whether it's of a type `U` using `hasUDA!(sym, U)` and
`getUDAs!(sym, U)`. Is the users uses `U()` or `U().func!0()`,
everything works. But `U().func!0` does not because its type is
not `U`. So to handle this use case it seems I need to
implement my own `hasUDA` and `getUDAs` based on
`ReturnType`.
My first instinct is to say that this is the user's mistake. UDAs
are not evaluated like normal expressions, and anyone using UDAs
is going to have to learn that sooner or later.
That said, if you want to try and present a nicer API, my
recommendation would be to accept *either* (a) an instance of
`U`, or (b) a callable that returns a `U`, which you can do with
code like the following:
```d
import std.traits, std.meta;
enum isOrReturnsU(alias attr) = is(typeof(attr) == U) ||
is(typeof(attr()) == U);
alias getMyUDAs(alias sym) = Filter!(isOrReturnsU, getUDAs!sym);
```
Or if you want to generalize to arbitrary predicates:
```d
alias filterUDAs(alias sym, alias pred) = Filter!(pred,
getUDAs!sym);
```