www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Dealing with raw types as attributes

reply Neia Neutuladh <neia ikeran.org> writes:
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?
Nov 01 2018
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Nov 01 2018
parent Neia Neutuladh <neia ikeran.org> writes:
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.
Nov 01 2018
prev sibling next sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
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); } } ```
Nov 01 2018
parent reply Neia Neutuladh <neia ikeran.org> writes:
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.
Nov 01 2018
parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
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.
Nov 01 2018
prev sibling next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
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
Nov 01 2018
parent reply Neia Neutuladh <neia ikeran.org> writes:
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?
Nov 01 2018
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
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))
Nov 01 2018
parent reply Neia Neutuladh <neia ikeran.org> writes:
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.
Nov 01 2018
parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Friday, 2 November 2018 at 04:18:47 UTC, Neia Neutuladh wrote:
 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.
template GetMeTheValue(value...) if(value.length == 1) { static if (is(typeof(value[0].init == value[0]) // A type enum GetMeTheValue = value[0].init; else enum GetMeTheValue = value[0]; } ... static if (is(typeof(GetMeTheValue!uda) == Foo)
Nov 01 2018
prev sibling parent Kagamin <spam here.lot> writes:
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;
IIRC symbol reference is a primary expression.
Nov 02 2018