www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - hasUDA with this

reply jmh530 <john.michael.hall gmail.com> writes:
I wanted to create a struct with a member function whose behavior 
was different depending on whether the struct instance had a 
particular UDA.

However, it seems like hasUDA doesn't seem to produce the result 
I would have expected here. I tried using getAttributes, but that 
didn't work either.

Am I missing something, or should I submit an enhancement request?



import std.traits : hasUDA;

enum test;

struct Foo
{
     int x;

     bool checkUDA()
     {
     	static if (hasUDA!(this, test))
         {
         	return true;
         }
         else
         {
         	return false;
         }
     }
}


void main()
{
     import std.stdio : writeln;

      test Foo foo = Foo(1);
     static assert(hasUDA!(foo, test));

     writeln(foo.checkUDA()); //prints false, expected true
}
Jul 19 2018
next sibling parent Timoses <timosesu gmail.com> writes:
On Thursday, 19 July 2018 at 19:18:43 UTC, jmh530 wrote:
 I wanted to create a struct with a member function whose 
 behavior was different depending on whether the struct instance 
 had a particular UDA.

 However, it seems like hasUDA doesn't seem to produce the 
 result I would have expected here. I tried using getAttributes, 
 but that didn't work either.

 Am I missing something, or should I submit an enhancement 
 request?



 import std.traits : hasUDA;

 enum test;

 struct Foo
 {
     int x;

     bool checkUDA()
     {
     	static if (hasUDA!(this, test))
         {
         	return true;
         }
         else
         {
         	return false;
         }
     }
 }


 void main()
 {
     import std.stdio : writeln;

      test Foo foo = Foo(1);
     static assert(hasUDA!(foo, test));

     writeln(foo.checkUDA()); //prints false, expected true
 }
I haven't worked with UDAs myself yet, but I believe that when you apply something like test Foo foo; then you apply the UDA to `foo` and not to `Foo`. See below: enum test; struct Foo {} bool checkUDA(alias f)() { static if (hasUDA!(f, test)) { return true; } else { return false; } } void main() { test Foo foo; // same as `hasUDA!(foo, test)` assert(checkUDA!foo); //prints true } Now I'm really not sure how UDAs are best utilized, so above example might not be how it should be done.. However, you could make a templated version of checkUDA depending on what calls it. E.g. bool checkUDA(T, alias f)(T t) { // ... } although this leads to awkward calls like foo.checkUDA!foo which doesn't seem right either. Perhaps wait for somebody more knowledgeable to answer your question : D.
Jul 19 2018
prev sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Thursday, 19 July 2018 at 19:18:43 UTC, jmh530 wrote:
 However, it seems like hasUDA doesn't seem to produce the 
 result I would have expected here. I tried using getAttributes, 
 but that didn't work either.

 Am I missing something, or should I submit an enhancement 
 request?
UDAs apply to symbols. When you pass something to a function, the symbol does not go with the value, and thus that UDA goes away. It's similar to assigning to a different variable: import std.traits : hasUDA; ("foo") Foo foo1; Foo foo2 = foo1; assert(!hasUDA!(foo2, "foo")); Since UDAs are compile-time constructs, they really can't follow values around in that way. Consider: void main(string[] args) { ("foo") Foo foo1; ("bar") Foo foo2; Foo foo3 = (args.length % 2) ? foo1 : foo2; assert(hasUDA!(foo3, "foo")); // Would you expect this to pass or fail? } Timoses first checkUDA function is exactly what I would suggest you use. -- Simen
Jul 20 2018
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Friday, 20 July 2018 at 07:25:23 UTC, Simen Kjærås wrote:
 UDAs apply to symbols. When you pass something to a function, 
 the symbol does not go with the value, and thus that UDA goes 
 away. It's similar to assigning to a different variable:

     import std.traits : hasUDA;
      ("foo")
     Foo foo1;
     Foo foo2 = foo1;
     assert(!hasUDA!(foo2, "foo"));

 Since UDAs are compile-time constructs, they really can't 
 follow values around in that way. Consider:

 void main(string[] args) {
      ("foo")
     Foo foo1;
      ("bar")
     Foo foo2;
     Foo foo3 = (args.length % 2) ? foo1 : foo2;
     assert(hasUDA!(foo3, "foo")); // Would you expect this to 
 pass or fail?
 }

 Timoses first checkUDA function is exactly what I would suggest 
 you use.

 --
   Simen
That the UDAs don't copy with the values potentially throws my idea into the crapper... Anyway, what I really wanted to do is change behavior of the struct, at compile-time, based on a UDA. For instance, what I really want is more like: struct Foo { static if (hasUDA!(this, DisableCasting)) { disable T opCast(T) { } } } So that if the instance has the particular UDA, then some kind of error would be thrown at compile-time that opCast was disabled. I don't really need anything at run-time. Obviously, I could do this as a template with a compile-time switch. I just wanted to see if it was possible with a UDA because then I could apply it to many different structs by just adding a template mixin of the above. I wouldn't need to make them different types. All functions that currently use them would work, unless there is a cast, in which case you know that at compile-time.
Jul 20 2018
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Friday, 20 July 2018 at 14:11:23 UTC, jmh530 wrote:
 On Friday, 20 July 2018 at 07:25:23 UTC, Simen Kjærås wrote:
 UDAs apply to symbols. When you pass something to a function, 
 the symbol does not go with the value, and thus that UDA goes 
 away. It's similar to assigning to a different variable:

     import std.traits : hasUDA;
      ("foo")
     Foo foo1;
     Foo foo2 = foo1;
     assert(!hasUDA!(foo2, "foo"));

 Since UDAs are compile-time constructs, they really can't 
 follow values around in that way. Consider:

 void main(string[] args) {
      ("foo")
     Foo foo1;
      ("bar")
     Foo foo2;
     Foo foo3 = (args.length % 2) ? foo1 : foo2;
     assert(hasUDA!(foo3, "foo")); // Would you expect this to 
 pass or fail?
 }

 Timoses first checkUDA function is exactly what I would 
 suggest you use.

 --
   Simen
That the UDAs don't copy with the values potentially throws my idea into the crapper... Anyway, what I really wanted to do is change behavior of the struct, at compile-time, based on a UDA. For instance, what I really want is more like: struct Foo { static if (hasUDA!(this, DisableCasting)) { disable T opCast(T) { } } } So that if the instance has the particular UDA, then some kind of error would be thrown at compile-time that opCast was disabled. I don't really need anything at run-time. Obviously, I could do this as a template with a compile-time switch. I just wanted to see if it was possible with a UDA because then I could apply it to many different structs by just adding a template mixin of the above. I wouldn't need to make them different types. All functions that currently use them would work, unless there is a cast, in which case you know that at compile-time.
Hmm, on that part about the attributes copying their values, I suppose it would be sufficient if I could apply the attributes to a group of declarations. However, it didn't seem to work properly for me with UDAs, and I noticed that even some of the examples in the spec don't compile. Below is taken from section 8.5 and doesn't compile with DMD 2.081.1. (here's a version on run.dlang.org: https://run.dlang.io/is/pKHoBA) void main() { const int foo = 7; static assert(is(typeof(foo) == const(int))); const { double bar = foo + 6; } static assert(is(typeof(bar) == const(double))); }
Jul 20 2018
parent reply Timoses <timosesu gmail.com> writes:
On Friday, 20 July 2018 at 16:53:12 UTC, jmh530 wrote:
 Hmm, on that part about the attributes copying their values, I 
 suppose it would be sufficient if I could apply the attributes 
 to a group of declarations. However, it didn't seem to work 
 properly for me with UDAs, and I noticed that even some of the 
 examples in the spec don't compile. Below is taken from section 
 8.5 and doesn't compile with DMD 2.081.1. (here's a version on 
 run.dlang.org: https://run.dlang.io/is/pKHoBA)

 void main()
 {
     const int foo = 7;
     static assert(is(typeof(foo) == const(int)));

     const
     {
         double bar = foo + 6;
     }
     static assert(is(typeof(bar) == const(double)));
 }
It works in module scope https://run.dlang.io/is/OQKYag I don't know why though...
Jul 20 2018
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Friday, 20 July 2018 at 18:24:11 UTC, Timoses wrote:
 [snip]

 It works in module scope

 https://run.dlang.io/is/OQKYag

 I don't know why though...
This was reported in 2013. IMO, it should be mentioned in the spec if they don't plan on changing it. https://issues.dlang.org/show_bug.cgi?id=11064
Jul 25 2018
parent reply Timoses <timosesu gmail.com> writes:
On Wednesday, 25 July 2018 at 21:17:38 UTC, jmh530 wrote:
 On Friday, 20 July 2018 at 18:24:11 UTC, Timoses wrote:
 [snip]

 It works in module scope

 https://run.dlang.io/is/OQKYag

 I don't know why though...
This was reported in 2013. IMO, it should be mentioned in the spec if they don't plan on changing it. https://issues.dlang.org/show_bug.cgi?id=11064
I don't think that bug report relates to the initial question (UDA not applying to run-time instance). Regarding this example void fun() { /*const*/ { double bar; } static assert(!is (typeof(bar))); } it would kind of violate that `bar` is declared within its own scoped block if the static assert failed just because `const` was applied to the block.
Jul 26 2018
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Thursday, 26 July 2018 at 08:08:17 UTC, Timoses wrote:
 On Wednesday, 25 July 2018 at 21:17:38 UTC, jmh530 wrote:
 On Friday, 20 July 2018 at 18:24:11 UTC, Timoses wrote:
(snip) I don't think that bug report relates to the initial question (UDA not applying to run-time instance).
True. But I was thinking about making a block that applies the UDA to everything within the block as a way to avoid the problem of copying the UDA to another variable.
 Regarding this example

 void fun() {
     /*const*/
     {
         double bar;
     }

     static assert(!is (typeof(bar)));
 }

 it would kind of violate that `bar` is declared within its own 
 scoped block if the static assert failed just because `const` 
 was applied to the block.
I don’t think the const block introduces a new scope. It works at the global level just fine. Public/private/etc are also a relevant example.
Jul 26 2018
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 07/26/2018 09:24 AM, jmh530 wrote:
 On Thursday, 26 July 2018 at 08:08:17 UTC, Timoses wrote:
 On Wednesday, 25 July 2018 at 21:17:38 UTC, jmh530 wrote:
 Regarding this example

 void fun() {
     /*const*/
     {
         double bar;
     }

     static assert(!is (typeof(bar)));
 }

 it would kind of violate that `bar` is declared within its own scoped
 block if the static assert failed just because `const` was applied to
 the block.
I don’t think the const block introduces a new scope.
It doesn't but the scope itself is legal in a nested scope; so, 'const' should not remove the scope either.
 It works at the
 global level just fine.
It must be because one cannot introduce a nested scope at the global scope: // illegal { double bar; } void main() { // legal { double bar; } } Ali
Jul 26 2018
parent jmh530 <john.michael.hall gmail.com> writes:
On Thursday, 26 July 2018 at 16:52:31 UTC, Ali Çehreli wrote:
 [snip]

 It doesn't but the scope itself is legal in a nested scope; so, 
 'const' should not remove the scope either.

 It works at the
 global level just fine.
It must be because one cannot introduce a nested scope at the global scope: // illegal { double bar; } void main() { // legal { double bar; } } Ali
We seem to be getting caught in scopes, when const: fails just as much as const {} does. The spec suggests that both of those work for all attributes including UDAs, when it only works on a limited subset outside of global scope.
Jul 30 2018