March 18, 2012
On 3/17/2012 8:12 PM, Adam D. Ruppe wrote:
> Walter, how do you feel about the compile time
> annotation list?

I feel it has merit, but I think it is possibly more complex than necessary.

Note that I have never used user defined attributes, so I don't have experience to guide me on this.

March 18, 2012
Walter Bright wrote:
> I mean there is modifiable-at-runtime, instance-specific data.

In C#, no there isn't. Attributes are simply objects constructed (when gotten) from an Entity's metadata. No memory is stored per-instance unless you manage the objects manually:

    class A : Attribute { public string s = "Default"; }

    [TestA] class C {}

    static void Main()
    {
        // The line below is equivalent to: var a = new A();
        // except that it's construction is defined by
        // metadata stored in type C.
        var a = typeof(C).GetCustomAttributes(true)[0] as A;
        a.s = "Modification";
        Console.WriteLine(a.s); // prints "Modification"

        // Therefor...
        var b = typeof(C).GetCustomAttributes(true)[0] as A;
        Console.WriteLine(b.s); // prints "Default"
    }

>> In that case, there's two
>> benefits I can think of over "traditional" member data: Instance memory
>> (attributes are create at reflection),
>
> Lazy initialization is a standard pattern. No special language features are needed for it.

I see how my statements (and code examples) where confusing. I meant that no attribute data is stored per-instance at all (unless traditionally done so), and that attribute objects are simply create in-place at the point of access. So to clarify my previous code a bit:

    attribute class A { string i = "Default"; }

    @A class C { A a; }

    void main()
    {
        auto a = C@A; // create new A based on C
        assert(is(typeof(a) : A));

        // alternatively you could do:
        auto c = new C();
        auto a = c@A; // same as: typeof(c)@A

        c.a = c@A; // explicitly store attribute
    }

Note: Might want to use the "new" keyword with class type attributes (auto a = new C@A), but the idea's there. Plus, I think that looks a lot better than the C# version.

>> and reusable metadata packages (similar
>> to how you might use mixin templates only with less noise and reflection capabilities).
>
> Sounds like a garden variety user-defined data type.

It is. Only it's a data type who's construction values are stored in metadata (per entity), and therefor can be used at both compile and run times. By per-entity I mean for each unique Type, Type member, Sub-Type, etc.

I don't know of any existing D idiom that is capable of what I presented. If there is, I would like to know. Here's the closest I can think of:

    mixin template CoolInt(bool cool, string name)
    {
        mixin("enum bool " ~ name ~ "_isCool = cool;");
        mixin("int " ~ name ~ ";");
    }

    class CoolClass
    {
        mixin CoolInt!(true, "a");
        mixin CoolInt!(false, "b");
    }

    void main()
    {
        auto c = new CoolClass();
        writeln(c.a_isCool); // true
        writeln(c.b_isCool); // false
    }

which, aside from noise, is great for runtime reflection, but it's completely useless (i think) for the compiler because the variables are created through arbitrary strings. Plus, I don't know how you'd store anything but simple variables, which more complex data would require a lot of <entity>_variables.
March 18, 2012
F i L wrote:
> Plus, I don't know how you'd store anything but simple variables, which more complex data would require a lot of <entity>_variables.

I found a way:

mixin template Attribute(
  string type,
  string name,
  string attr,
  Params...)
{
    mixin (type ~ " " ~ name ~ ";");
    mixin (
        "auto " ~ name ~ "_" ~ attr ~ "()" ~
        "{ return new " ~ attr ~ "(Params); }"
    );
}

class Cool
{
    string s;
    this(string s)
    {
        this.s = s;
    }
}

class CoolClass
{
    mixin Attribute!("int", "a", "Cool", "Heh");
    mixin Attribute!("int", "b", "Cool", "Sup");
}

void main()
{
    auto c = new CoolClass();
    writeln(c.a, ", ", c.b); // 0, 0
    writeln(c.a_Cool().s); // Heh
    writeln(c.b_Cool().s); // Sup
}

March 18, 2012
On Sunday, 18 March 2012 at 10:25:20 UTC, F i L wrote:
> F i L wrote:
> class CoolClass
> {
>     mixin Attribute!("int", "a", "Cool", "Heh");
>     mixin Attribute!("int", "b", "Cool", "Sup");
> }
>
> void main()
> {
>     auto c = new CoolClass();
>     writeln(c.a, ", ", c.b); // 0, 0
>     writeln(c.a_Cool().s); // Heh
>     writeln(c.b_Cool().s); // Sup
> }

Is it not possible to alias a mixin to just one letter, and then use it to have any syntax we want... something like this:

x("@attribute(Serializable.yes) int a");


March 18, 2012
On Sunday, 18 March 2012 at 10:38:19 UTC, Tove wrote:
> On Sunday, 18 March 2012 at 10:25:20 UTC, F i L wrote:
>> F i L wrote:
>> class CoolClass
>> {
>>    mixin Attribute!("int", "a", "Cool", "Heh");
>>    mixin Attribute!("int", "b", "Cool", "Sup");
>> }
>>
>> void main()
>> {
>>    auto c = new CoolClass();
>>    writeln(c.a, ", ", c.b); // 0, 0
>>    writeln(c.a_Cool().s); // Heh
>>    writeln(c.b_Cool().s); // Sup
>> }
>
> Is it not possible to alias a mixin to just one letter, and then use it to have any syntax we want... something like this:
>
> x("@attribute(Serializable.yes) int a");

Sure, but there's still the issue of using attributes for codegen. For instance compare:

    struct Test {
        @GC.NoScan int value;
    }

to, the current:

    struct Test {
        int value;
        this() { GC.setAttr(&value, NO_SCAN); }
    }

How can we do that with mixin templates? If attributes where a language type the compiler could exploit in a consistent way, It would be *trivial* describing this behavior in a declarative way.
March 18, 2012
F i L wrote:
>     struct Test {
>         int value;
>         this() { GC.setAttr(&value, NO_SCAN); }
>     }

bleh, should be...

    struct Test {
        int value;
        this(int v) { GC.setAttr(&value, GC.BlkAttr.NO_SCAN); }
    }

Or something like that. I've never actually set GC attributes before.

But this also raises another issue. Structs don't have default constructors, so applying NoScan attributes (by default) is, to my knowledge, impossible. Whereas it could (?) be possible through attributes.
March 18, 2012
On Sunday, 18 March 2012 at 10:50:14 UTC, F i L wrote:
>> x("@attribute(Serializable.yes) int a");
>
> Sure, but there's still the issue of using attributes for codegen. For instance compare:
>
>     struct Test {
>         @GC.NoScan int value;
>     }
>
> to, the current:
>
>     struct Test {
>         int value;
>         this() { GC.setAttr(&value, NO_SCAN); }
>     }
>
> How can we do that with mixin templates? If attributes where a language type the compiler could exploit in a consistent way, It would be *trivial* describing this behavior in a declarative way.

Hmm... well if the x declarations store all NoScan objects in a collection, it could be injected into the constructor token stream later...

x!("@GC.NoScan int value;");

// modified by x to insert a foreach with GC.setAttr
x!(q{this() {/* foreach(...) GC.setAttr(...); */ });

But I guess one lose the opportunity for some compile time magic... in a more efficient way than exposed by the GC.settAttr API.(just pure speculation, I don't have sufficient knowledge of the internal representation of our GC design.).



March 18, 2012
On 18 March 2012 05:04, Kapps <opantm2+spam@gmail.com> wrote:

> On Sunday, 18 March 2012 at 01:48:07 UTC, Walter Bright wrote:
>
>> On 3/17/2012 6:39 PM, Manu wrote:
>>
>>> I'm sure C# already answers all these questions. It has precisely the
>>> same set
>>> of issues associated.
>>>
>>
>> C# doesn't have RAII, immutable, nor the notion of threadlocal/shared types.
>>
>
> It has threadlocal using the [ThreadLocal] attribute which gets implemented by the compiler.
>
> In C#, all attributes live inside the TypeInfo/MethodInfo/etc for the class/struct/method/field/**parameter. I don't see this being a problem. I can't think of good use cases where an attribute/annotation should be per-instance at all, particularly with the compile-time power that D has, whereas C# does not have any. Honestly, most uses of attributes in D would be done at compile-time, and I think that's acceptable until/if runtime reflection is put in. If it is needed, it can live inside TypeInfo/MethodInfo, but is (imo) absolutely not needed on a per-instance basis. This is the job of fields or interfaces.
>

I think that's a fair call. I wonder why Java feels the need for stateful
attributes.
I have made extensive use of java attributes that have been stateful.
Java's persistence api's rely on stateful attributes a lot, but I think
that can be done in other ways in D.

Compile-time attributes sound like a great start, it's much simpler. But they do need to be able to 'do stuff', ie, add some property/method to a field (using the field its self as the context pointer), not just simply 'tag' it.


March 18, 2012
Tove wrote:
> Hmm... well if the x declarations store all NoScan objects in a collection, it could be injected into the constructor token stream later...
>
> x!("@GC.NoScan int value;");
>
> // modified by x to insert a foreach with GC.setAttr
> x!(q{this() {/* foreach(...) GC.setAttr(...); */ });

But if x!() pumps out a constructor, how do you add multiple attributes with @GC.NoScan? The constructors would collide.


March 18, 2012
On Sunday, 18 March 2012 at 12:10:23 UTC, F i L wrote:
> Tove wrote:
>> Hmm... well if the x declarations store all NoScan objects in a collection, it could be injected into the constructor token stream later...
>>
>> x!("@GC.NoScan int value;");
>>
>> // modified by x to insert a foreach with GC.setAttr
>> x!(q{this() {/* foreach(...) GC.setAttr(...); */ });
>
> But if x!() pumps out a constructor, how do you add multiple attributes with @GC.NoScan? The constructors would collide.

1. x! would parse all decls at compile time...
2. all attributes that need to modify the constructor is inserted at the points where the x! enabled constructors are declared/implemented...

x!("@GC.NoScan @GC.Hot @attribute(Serializable.yes) int value;");

x!(q{this()
{
  /* everything from 'x' is auto inserted here */
  my;
  normal;
  constructor;
  tokens;
});