March 18, 2012
Tove wrote:
> 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;
> });

I see, that would work. But why not just build this same operation into the compiler so the definition syntax is the same as usual. The mixin's are powerful but a bit ugly. Not to mention not IDE parser on the planet is going to be able to figure out all that to give you intelligent code-completion.

March 18, 2012
On Sunday, 18 March 2012 at 12:39:19 UTC, F i L wrote:
> Tove wrote:
>> 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;
>> });
>
> I see, that would work. But why not just build this same operation into the compiler so the definition syntax is the same as usual. The mixin's are powerful but a bit ugly. Not to mention not IDE parser on the planet is going to be able to figure out all that to give you intelligent code-completion.

Yes, I was thinking along these lines... what would be the absolutely bare minimum needed support this from the compiler to make this "scheme" look first class?

what if... the compiler encounters an unknown @token then it would delegate the parsing to a library implementation... which basically would do the above, but it would be hidden from the user... this way we would get a 0 effort(from the perspective of the compiler) and extensible syntax in library covering all future needs.

March 18, 2012
On 3/18/2012 2:47 AM, F i L wrote:
> 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"
> }

Which looks indistinguishable from modifiable at runtime, instance specific data.


>> 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.

Sorry, it still looks like standard lazy initialization. I don't know what attributes add to the party.


>> 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.

Simply use a normal class. Instantiate it at runtime as needed.


> 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.

Something like Jacob's proposal for compile time attributes would be useful here. My failure to understand is about runtime attributes.
March 18, 2012
On 2012-03-18 20:26, Walter Bright wrote:

> Something like Jacob's proposal for compile time attributes would be
> useful here. My failure to understand is about runtime attributes.

If we'll get user defined attributes that is accessible via runtime reflection I'm sure people will find uses cases for it that are not possible with compile time reflection. But currently I don't see any use cases for attributes per instance.

If I'm thinking correctly this can be used for serializing. Say that you want to serialize an object through a base class reference. Currently you will need to register the subclass using some mechanism due to the limited runtime reflection in D. But if it would be possible to enumerate all fields in a class and also set and get the values of the fields using runtime reflection it wouldn't be necessary to register the subclass.

Ok, now to the user defined attribute:

@attribute class NonSerialized {} // This is what's called a "marker" in Java. It doesn't contain any information, the information is the type itself.

@attribute class SerializeAs
{
    string value;
}

class Base
{
    int x;
    @SerializeAs(foo) int y;
    @NonSerialized int c;
}

@NonSerialized class Sub : Base
{
    int z;
}

Base sub = new Sub;
serialize(sub);

In this example the user defined attribute "NonSerialized" indicates that the class shouldn't be serialized. When the serializer is serializing "sub" the compile time type will be "Base" therefore it would need to use runtime reflection to also serialize the fields added in the subclass "Sub". To check if the object should be serialized the serializer need to be able to access user defined attributes using runtime reflection. Something like:

auto classInfo = sub.classinfo;
writeln(classInfo); // Sub

if (classInfo.hasAttribute("NonSerialized"))
    // skip serialization

else
{
    foreach (field ; classInfo.fields)
        if (!field.hasAttribute("NonSerialized"))
        {
            auto value = filed.value;
            string name;

            if (attribute = filed.attributes["SerializeAs"])
                name = attribute.value;

            else
                name = filed.name;

            // serialize the field
        }
}

We do all this during runtime because we want to serialize through base class references. If the runtime type is the same as the compile time type we can do this at compile time.

-- 
/Jacob Carlborg
March 19, 2012
On 3/18/2012 2:58 PM, Jacob Carlborg wrote:
> Ok, now to the user defined attribute:
>
> @attribute class NonSerialized {} // This is what's called a "marker" in Java.
> It doesn't contain any information, the information is the type itself.
>
> @attribute class SerializeAs
> {
> string value;
> }
>
> class Base
> {
> int x;
> @SerializeAs(foo) int y;
> @NonSerialized int c;
> }
>
> @NonSerialized class Sub : Base
> {
> int z;
> }
>
> Base sub = new Sub;
> serialize(sub);
>
> In this example the user defined attribute "NonSerialized" indicates that the
> class shouldn't be serialized. When the serializer is serializing "sub" the
> compile time type will be "Base" therefore it would need to use runtime
> reflection to also serialize the fields added in the subclass "Sub". To check if
> the object should be serialized the serializer need to be able to access user
> defined attributes using runtime reflection.

I'm sorry, I find this *massively* confusing. What is foo? Why are you serializing something marked "NonSerialized"? I really have no idea what is going on with this. What is the serialize() function? How does any of this tell you how to serialize an int? How is Base.c also a NonSerialized with c in a superclass of it?

??????????????????????????????????

Maybe this is why I don't much care for attributes - it's all just a fog to me what is happening.
March 19, 2012
On Friday, 16 March 2012 at 13:35:55 UTC, Adam D. Ruppe wrote:
> On the ride over here today, I had a thought that
> I think neatly solves the user defined attribute
> question.

Maybe there are other ways to think about user defined attributes. I'd like them to essentially be ways to extend the static type system in library code.

I am thinking about things like the ones done by Dehydra and Treehydra (https://developer.mozilla.org/en/Dehydra  https://developer.mozilla.org/en/Treehydra ) but using the D language itself instead of JavaScript.

This asks for more __traits(...), to allow the D programmer (that is defining a new attribute) to use them to static verify more characteristics of the D code being annotated with the attributes.

Bye,
bearophile
March 19, 2012
Walter Bright wrote:
> I'm sorry, I find this *massively* confusing. What is foo? Why are you serializing something marked "NonSerialized"? I really have no idea what is going on with this. What is the serialize() function?

He's giving an example of serialize() below the code you quoted.



Walter Bright wrote:
> Which looks indistinguishable from modifiable at runtime,
> instance specific data.

If you're *only* considering the runtime ability of attributes, then it is. This:

    attribute struct A { this(int x, int y); void foo(); }
    @A(1, 2) struct C {}

    void main() {
        auto a = C@A;
        a.foo();
    }

would be conceptually equivalent to writing:

    struct A { this(int x, int y); void foo(); }
    struct C { static auto _A() { return A(1, 2); } }

    void main() {
        auto a = C._A();
        a.foo();
    }

and it's my fault for not illustrating the important difference in the first place. Which is: Attributes are understandable by the compiler, therefor, attributes can describe behavior of an entity and inject code into key places where that entity is allocated/constructed/etc. For instance, C# does not directly support Unions, however creating the structure is possible, like so:

    [StructLayout(LayoutKind.Explicit)]
    struct MyUnion
    {
        [FieldOffset(0)] int a;
        [FieldOffset(0)] long b;
        [FieldOffset(0)] float c;
    }


Because Attributes are defined with unique syntax, they can be stored uniquely by the compiler, and then reacted upon _in a variety of ways_. They are available at runtime so that runtime code can react to them as well.

To illustrate what Trove and I have been talking about, If I wanted to "mark" a variable so that the GC wouldn't scan it, I might be able to write something like:

    attribute class Memory {
        GC.BlkAttr blkAttr;

        this(GC.BlkAttr attr) { blkAttr = attr; }

        @this(void* entity) {
            // the code in this function gets injected into
            // this() of the entity this class is attached to

            GC.setAttr(entity, blkAttr);
        }
    }

The "@this(void*)" function might always take in a void* (much like how new() always takes uint/size_t) which points to the entity it's attributing. So if we then write:

    @Memory(GC.BlkAttr.NO_SCAN) string myString;

Then when "myString.init()" is called,
"GC.setAttr(myString, GC.BlkAttr.NO_SCAN)" will also be executed. I don't know enough about DMD's internals to know about how this would play out internally, but the concept is there.

And I know my syntax has be changing over the last few posts (I've been going through different ideas), so I apologize if I'm being hard to follow here.
March 19, 2012
Am 19.03.2012 01:41, schrieb Walter Bright:
> I'm sorry, I find this *massively* confusing. What is foo? Why are you
> serializing something marked "NonSerialized"? I really have no idea what is
> going on with this. What is the serialize() function? How does any of this tell
> you how to serialize an int? How is Base.c also a NonSerialized with c in a
> superclass of it?

attributes does not containing code - there just a (at-runtime) queryable information that can be attached to serveral things (like classes, methods, ...) - think of it like double.epsilon - but extendable by users - thats it, and in the c# world these attribute-definitions tend to be something like an class (but without code)

in c# you can walk by (runtime)reflection through your code and find out if something is annotated with an special attribute and use the configure information and do something with it - call an constructor, open an connection, generated code (at runtime) - whatever you want

its a easy-to-use-buildin-attribution-system thats it - and people like them because c# do all the big magic by giving developers a bunch of attributes that are then used for stuff like serialization, memory-layout, ...

a compiletime example of this could be:

attribute my_special_attribute
{
   int version;
}

attribute my_special_attribute2
{
   string test;
}

class test
{
   [my_special_attribute(version=2)]
   int method1();

   [my_special_attribute(version=2)]
   [my_special_attribute2(test="bert")]
   int method2();
}

void main()
{
  auto b = [ __traits(allMembers, D) ];
  foreach( auto a; b )
  {
    -->attribute query magic
    -->auto c = [ __traits(attribute("my_special_attribute", a) ];
    -->auto c = [ __traits(attribute("my_special_attribute2", a) ];

    //now we know all methods with my_special_attribute
    //and speical_special_attribute2 and their content (version=2
    //and test="bert"

    //now think of an template or mixing that uses this
    //information for code-generation or something like that

    //thats all
  }
}




March 19, 2012
Except for shared types, since in C# data is shared by default, everything
else is available:

RAII            -> using ()
immutable -> achieved via cons/readonly (good enough for most purposes)
ThreadLocal -> ThreadLocal<T> class

"Walter Bright"  wrote in message news:jk3esn$1697$1@digitalmars.com...

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. 

March 19, 2012
On Monday, 19 March 2012 at 06:46:09 UTC, dennis luehring wrote:
> Am 19.03.2012 01:41, schrieb Walter Bright:
>> I'm sorry, I find this *massively* confusing. What is foo? Why are you
>> serializing something marked "NonSerialized"? I really have no idea what is
>> going on with this. What is the serialize() function? How does any of this tell
>> you how to serialize an int? How is Base.c also a NonSerialized with c in a
>> superclass of it?
>
> attributes does not containing code - there just a (at-runtime) queryable information that can be attached to serveral things (like classes, methods, ...) - think of it like double.epsilon - but extendable by users - thats it, and in the c# world these attribute-definitions tend to be something like an class (but without code)
>
> in c# you can walk by (runtime)reflection through your code and find out if something is annotated with an special attribute and use the configure information and do something with it - call an constructor, open an connection, generated code (at runtime) - whatever you want
>
> its a easy-to-use-buildin-attribution-system thats it - and people like them because c# do all the big magic by giving developers a bunch of attributes that are then used for stuff like serialization, memory-layout, ...
>
> a compiletime example of this could be:
>
> attribute my_special_attribute
> {
>    int version;
> }
>
> attribute my_special_attribute2
> {
>    string test;
> }
>
> class test
> {
>    [my_special_attribute(version=2)]
>    int method1();
>
>    [my_special_attribute(version=2)]
>    [my_special_attribute2(test="bert")]
>    int method2();
> }
>
> void main()
> {
>   auto b = [ __traits(allMembers, D) ];
>   foreach( auto a; b )
>   {
>     -->attribute query magic
>     -->auto c = [ __traits(attribute("my_special_attribute", a) ];
>     -->auto c = [ __traits(attribute("my_special_attribute2", a) ];
>
>     //now we know all methods with my_special_attribute
>     //and speical_special_attribute2 and their content (version=2
>     //and test="bert"
>
>     //now think of an template or mixing that uses this
>     //information for code-generation or something like that
>
>     //thats all
>   }
> }

Well I was thinking if we can go one step further than C#, because of D:s CTFE... by introducing a call back from the D compiler to the library CTFE attribute handler... this way we can hide all reflection from the "end user"... and the compiler doesn't need to know anything at all, as the library does the semantic lowering.

@GC.NoScan int value;
@GC this() {}

Compiler Asks library for transformation of unknown @GC
bool library("@GC this() {anything...}") ->

if the library succeeds it would then transform the string and hand back a lowered mixin to the compiler.

mixin("
this()
{
  auto b = [ __traits(allMembers, D) ];
  foreach( auto a; b) {DO.GC.Stuff...}

  anything...
}
");