Jump to page: 1 2
Thread overview
hasUDA with this
Jul 19, 2018
jmh530
Jul 20, 2018
Timoses
Jul 20, 2018
Simen Kjærås
Jul 20, 2018
jmh530
Jul 20, 2018
jmh530
Jul 20, 2018
Timoses
Jul 25, 2018
jmh530
Jul 26, 2018
Timoses
Jul 26, 2018
jmh530
Jul 26, 2018
Ali Çehreli
Jul 30, 2018
jmh530
July 19, 2018
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
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
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
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
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
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
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
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
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
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

« First   ‹ Prev
1 2