Thread overview |
---|
July 19, 2018 hasUDA with this | ||||
---|---|---|---|---|
| ||||
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 } |
July 20, 2018 Re: hasUDA with this | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | 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.
|
July 20, 2018 Re: hasUDA with this | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | 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
|
July 20, 2018 Re: hasUDA with this | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | 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.
|
July 20, 2018 Re: hasUDA with this | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | 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))); } |
July 20, 2018 Re: hasUDA with this | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | 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... |
July 25, 2018 Re: hasUDA with this | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timoses | 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 |
July 26, 2018 Re: hasUDA with this | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | 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.
|
July 26, 2018 Re: hasUDA with this | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timoses | 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. |
July 26, 2018 Re: hasUDA with this | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | 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 |
Copyright © 1999-2021 by the D Language Foundation