Jump to page: 1 2
Thread overview
Dealing with raw types as attributes
Nov 01, 2018
Neia Neutuladh
Nov 01, 2018
Ali Çehreli
Nov 01, 2018
Neia Neutuladh
Nov 01, 2018
Stanislav Blinov
Nov 01, 2018
Neia Neutuladh
Nov 01, 2018
Stanislav Blinov
Nov 02, 2018
Nicholas Wilson
Nov 02, 2018
Neia Neutuladh
Nov 02, 2018
Nicholas Wilson
Nov 02, 2018
Neia Neutuladh
Nov 02, 2018
Nicholas Wilson
Nov 02, 2018
Kagamin
November 01, 2018
The spec says that a user-defined attribute must be an expression, but DMD accepts a wide range of things as UDAs:

  struct Foo { string name = "unknown"; }
  @Foo int bar;

`bar` has the *type* Foo as an attribute. It's not an *instance* of Foo. So if I try to look at the UDAs:

  static foreach (uda; __traits(getAttributes, bar))
  {
    static if (is(typeof(uda) == Foo))
    {
      pragma(msg, "bar is @Foo");
    }
  }

That just doesn't work; typeof(Foo) isn't anything, so is(typeof(Foo) == Foo) is false.

I can change my code to read `static if (is(uda == Foo))`. But that obviously fails:

  @Foo("customName") int bar2;

What do you do to handle this?

My current workaround is to make the attribute into a struct instance and use opCall in lieu of constructors:

  struct _Foo
  {
    string name;
    _Foo opCall(string name)
    {
      _Foo f;
      f.name = name;
      return f;
    }
  }
  enum _Foo Foo = _Foo.init;

Now I can use `static if (is(typeof(uda) == _Foo))` and it always works. But are there better options? Any obvious flaws?
November 01, 2018
On 11/01/2018 09:14 AM, Neia Neutuladh wrote:
> The spec says that a user-defined attribute must be an expression, but DMD
> accepts a wide range of things as UDAs:
> 
>    struct Foo { string name = "unknown"; }
>    @Foo int bar;
> 
> `bar` has the *type* Foo as an attribute. It's not an *instance* of Foo.
> So if I try to look at the UDAs:

That would work with hasUDA(). I have an example here:

  http://ddili.org/ders/d.en/uda.html

Ali
November 01, 2018
On Thursday, 1 November 2018 at 16:14:45 UTC, Neia Neutuladh wrote:
> The spec says that a user-defined attribute must be an expression, but DMD accepts a wide range of things as UDAs:
>
>   struct Foo { string name = "unknown"; }
>   @Foo int bar;
>
> `bar` has the *type* Foo as an attribute. It's not an *instance* of Foo. So if I try to look at the UDAs:
>
>   static foreach (uda; __traits(getAttributes, bar))
>   {
>     static if (is(typeof(uda) == Foo))
>     {
>       pragma(msg, "bar is @Foo");
>     }
>   }
>
> That just doesn't work; typeof(Foo) isn't anything, so is(typeof(Foo) == Foo) is false.
>
> I can change my code to read `static if (is(uda == Foo))`. But that obviously fails:
>
>   @Foo("customName") int bar2;
>
> What do you do to handle this?

Check if an UDA is a type?.. As in, not just `is(uda == Foo)`, but simply `is(uda)`:

```
struct Foo { string name = "unknown"; }
@Foo @string @Foo("hello") int bar;

static foreach (uda; __traits(getAttributes, bar)) {
    static if (is(uda)) {
        // if `uda` is a type...
        static if (is(uda == Foo)) {
            pragma(msg, "bar is @Foo!!!");
        } else {
            pragma(msg, "bar is "~uda.stringof);
        }
    } else {
        // if `uda` is not a type...
        pragma(msg, "bar is "~uda.stringof);
    }
}
```
November 01, 2018
On Thu, 01 Nov 2018 11:35:27 -0700, Ali Çehreli wrote:
> On 11/01/2018 09:14 AM, Neia Neutuladh wrote:
>> The spec says that a user-defined attribute must be an expression, but DMD accepts a wide range of things as UDAs:
>> 
>>    struct Foo { string name = "unknown"; }
>>    @Foo int bar;
>> 
>> `bar` has the *type* Foo as an attribute. It's not an *instance* of Foo. So if I try to look at the UDAs:
> 
> That would work with hasUDA(). I have an example here:
> 
>    http://ddili.org/ders/d.en/uda.html

That lets me test for presence, nothing more. While that's useful, I usually have a UDA struct whose fields I need to access.

std.traits.getUDAs doesn't hide the difference between @Foo and @Foo(), so that's also not an option. I could use a customized version of that that replaces @Type with @Type.init, and that's a reasonable choice when I know other people aren't going to deal with that annotation type.
November 01, 2018
On Thu, 01 Nov 2018 20:01:51 +0000, Stanislav Blinov wrote:
> Check if an UDA is a type?.. As in, not just `is(uda == Foo)`,
> but simply `is(uda)`:

Which works, but generally makes things more complex in code that's already pretty deeply nested. It's also something I have to worry about every time I do the static foreach to get UDAs, in the cases where that's more than once.
November 01, 2018
On Thursday, 1 November 2018 at 20:33:10 UTC, Neia Neutuladh wrote:
> On Thu, 01 Nov 2018 20:01:51 +0000, Stanislav Blinov wrote:
>> Check if an UDA is a type?.. As in, not just `is(uda == Foo)`,
>> but simply `is(uda)`:
>
> Which works, but generally makes things more complex in code that's already pretty deeply nested. It's also something I have to worry about every time I do the static foreach to get UDAs, in the cases where that's more than once.

Yes, it does :(

>  I could use a customized version of [getUDAs] that replaces @Type with @Type.init, and that's a reasonable choice...

That can't be generic, as you can have UDAs that don't have an .init:

enum XXX;

@XXX int bar;

static foreach (uda; __traits(getAttributes, bar)) {
    static if (is(uda == XXX)) {
        pragma(msg, "bar is XXX");
    }
}

...but so long as you can live without such UDAs, I guess it could work.
November 02, 2018
On Thursday, 1 November 2018 at 16:14:45 UTC, Neia Neutuladh wrote:
> The spec says that a user-defined attribute must be an expression, but DMD accepts a wide range of things as UDAs:
>

Indeed UDA are odd beasts: https://issues.dlang.org/show_bug.cgi?id=19127

> What do you do to handle this?

@Foo() int bar;

instead of

@Foo int bar;

https://run.dlang.io/is/3USj6h
November 02, 2018
On Fri, 02 Nov 2018 00:36:18 +0000, Nicholas Wilson wrote:
>> What do you do to handle this?
> 
> @Foo() int bar;
> 
> instead of
> 
> @Foo int bar;

Right. And if you're offering a library with UDAs for other people to use?
November 02, 2018
On Friday, 2 November 2018 at 03:13:19 UTC, Neia Neutuladh wrote:
> On Fri, 02 Nov 2018 00:36:18 +0000, Nicholas Wilson wrote:
>>> What do you do to handle this?
>> 
>> @Foo() int bar;
>> 
>> instead of
>> 
>> @Foo int bar;
>
> Right. And if you're offering a library with UDAs for other people to use?

I mean I suppose if you really wanted to avoid the parentheses, you could do

  static foreach (uda; __traits(getAttributes, bar))
  {
    static if (is(typeof(uda.init) == Foo)
    {
      pragma(msg, "bar is @Foo");
    }
  }

By noting that all (interesting for the purpose of UDA's i.e. not void) types have a .init

or you could do

static if (is(typeof(uda) == Foo) || is(uda == Foo))
November 02, 2018
On Fri, 02 Nov 2018 04:01:00 +0000, Nicholas Wilson wrote:
> By noting that all (interesting for the purpose of UDA's i.e. not void)
> types have a .init
> 
> or you could do
> 
> static if (is(typeof(uda) == Foo) || is(uda == Foo))

Which, again, only tests for presence, when I want to check for presence *and* get the value, which should be Foo.init if the person supplied the raw type.
« First   ‹ Prev
1 2