Thread overview
Weird behavior with UDAs
Jun 13, 2020
realhet
Jun 13, 2020
Adam D. Ruppe
Jun 13, 2020
realhet
Jun 13, 2020
Stanislav Blinov
June 13, 2020
Hello, I have a problem I can't even understand with the code below:

https://run.dlang.io/is/7yXAEA

import std.stdio, std.range, std.algorithm, std.traits, std.meta;

struct UNIFORM{ string name; }

struct A{
    int i1;
    @UNIFORM() int i2;
    @UNIFORM("fuzz") int i3;
    @UNIFORM int i4;
}

template getUDA(alias a, U){
  static if(hasUDA!(a, U)) enum getUDA = getUDAs!(a, U)[$-1];
                      else enum getUDA = U.init;
}

pragma(msg, getUDA!(A.i1, UNIFORM)); //UNIFORM(null)
pragma(msg, getUDA!(A.i2, UNIFORM)); //UNIFORM(null)
pragma(msg, getUDA!(A.i3, UNIFORM)); //UNIFORM("fuzz");
pragma(msg, getUDA!(A.i4, UNIFORM)); //Error: initializer must be an expression, not UNIFORM

struct UNIFORM2{ string name=""; }
struct B{ @UNIFORM2() int i1; }

pragma(msg, getUDA!(B.i1, UNIFORM2)); //UNIFORM("") instead if UNIFORM(null)

//------------------------------------------------------------------------

My first question is, how to avoid that error with A.i4?  Why is there a difference between @UNIFORM and @UNIFORM(), do the first returns a type and the later returns a value?

My second quertion is, why the UNIFORM struct with uninitialized string producing UNIFORM(null).
How can be a difference when I say name="", and it's just the same as the default string initializer, and then it produce UNIFORM("")?

Thank You!

June 13, 2020
On Saturday, 13 June 2020 at 12:55:36 UTC, realhet wrote:
> My first question is, how to avoid that error with A.i4?  Why is there a difference between @UNIFORM and @UNIFORM(), do the first returns a type and the later returns a value?

Basically yeah. a UDA in D is just whatever you write gets directly attached - it does no additional processing. So if you give it a type, it keeps a type. If a value, it keeps the value.

The simplest answer is probably "don't do that"; if it is meant to be a value, always give it a value.

But you could also write your own get UDA thing that recognizes the type (the check: static if(is(attribute)) for a type vs static if(is(typeof(attribute))) for the value) and returns the init value if you want in your code.

> My second quertion is, why the UNIFORM struct with uninitialized string producing UNIFORM(null).
> How can be a difference when I say name="", and it's just the same as the default string initializer, and then it produce UNIFORM("")?

null and "" can be used interchangeably and sometimes yield the same thing, but they aren't exactly the same.

Since you specified it there in the definition as a default value in a struct the compiler used that distinction. I'd suggest you write what you mean even in cases where it is the same so you cover the bases.

If you specifically want null, check `str is null` and use ` = null`. If either is fine, just use `str.length == 0`.
June 13, 2020
On Saturday, 13 June 2020 at 12:55:36 UTC, realhet wrote:
> Hello, I have a problem I can't even understand with the code

For the first I realized that an UDA can be a type too, and come up with this:

template getUDA(alias a, U){
  enum u = q{ getUDAs!(a, U)[$-1] };
    static if(hasUDA!(a, U) && !is(mixin(u)))
      enum getUDA = mixin(u);
    else
      enum getUDA = U.init;
}

So I always get an instance of the UDA with the default values.

But the second question is still beyond me:

How can be a string represented with 'null' by default instead on `""`. Unless I state it explicitly with name="" ? o.O
June 13, 2020
On Saturday, 13 June 2020 at 13:08:29 UTC, realhet wrote:

> How can be a string represented with 'null' by default instead on `""`. Unless I state it explicitly with name="" ? o.O

Because string is simply `alias string = immutable(char)[]`, and default initializer for arrays is null.