View mode: basic / threaded / horizontal-split · Log in · Help
March 18, 2012
Re: Proposal: user defined attributes
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
Re: Proposal: user defined attributes
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
Re: Proposal: user defined attributes
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
Re: Proposal: user defined attributes
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
Re: Proposal: user defined attributes
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
Re: Proposal: user defined attributes
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
Re: Proposal: user defined attributes
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
Re: Proposal: user defined attributes
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
Re: Proposal: user defined attributes
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
Re: Proposal: user defined attributes
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;
});
1 2 3 4 5 6 7 8 9
Top | Discussion index | About this forum | D home