November 06, 2012
References:

http://www.digitalmars.com/d/archives/digitalmars/D/Custom_attributes_again_163042.html

http://www.digitalmars.com/d/archives/digitalmars/D/custom_attribute_proposal_yeah_another_one_163246.html

Inspired by a gallon of coffee, I decided to get it implemented. It's simple, based on what D already does (CTFE and heterogeneous tuples), easy to implement, easy to understand, and doesn't break anything. It should do everything asked for in the above references (except it's not a type constructor).

You can download it here and try it out:

http://ftp.digitalmars.com/dmd2beta.zip

As a bonus, that beta also can generate Win64 executables, and you can even symbolically debug them with VS! (Thanks to Rainer Schütze for his invaluable help with that).

Here's the rather skimpy and lame spec I banged out:
=====================================================
User Defined Attributes
-----------------------

User Defined Attributes (UDA) are compile time expressions that can be attached
to a declaration. These attributes can then be queried, extracted, and manipulated
at compile time. There is no runtime component to them.

Grammatically, a UDA is a StorageClass:

    StorageClass:
	UserDefinedAttribute

    UserDefinedAttribute:
        [ ArgumentList ]

And looks like:

    [ 3 ] int a;
    [ "string", 7 ]: int b;

If there are multiple UDAs in scope for a declaration, they are concatenated:

    [ 1 ] {
       [ 2 ] int a;        // has UDA's [1,2]
       [ "string" ] int b; // has UDA's [1,"string"]
    }

UDA's can be extracted into an expression tuple using __traits:

    [ 'c' ] string s;
    pragma(msg, __traits(getAttributes, s));

prints:

    tuple('c')

If there are no user defined attributes for the symbol, an empty tuple is returned.
The expression tuple can be turned into a manipulatable tuple:

  template Tuple(T...) {
    alias T Tuple;
  }

  enum EEE = 7;
  ["hello"] struct SSS { }
  [3] { [4][EEE][SSS] int foo; }

  alias Tuple!(__traits(getAttributes, foo)) TP;

  pragma(msg, TP);
  pragma(msg, TP[2]);

prints:

  tuple(3,4,7,(SSS))
  7

and of course the tuple types can be used to declare things:

  TP[3] a;    // a is declared as an SSS

The attribute of the type name is not the same as the attribute of the variable:

  pragma(msg, __traits(getAttributes, typeof(a));

prints:

    tuple("hello")

Of course, the real value of UDA's is to be able to create user defined types with
specific values. Having attribute values of basic types does not scale.
The attribute tuples can be manipulated like any other tuple, and
can be passed as the argument list to a template.

Whether the attributes are values or types is up to the user, and whether later
attributes accumulate or override earlier ones is also up to how the user interprets them.
November 06, 2012
On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:
> References:
>
> http://www.digitalmars.com/d/archives/digitalmars/D/Custom_attributes_again_163042.html
>
> http://www.digitalmars.com/d/archives/digitalmars/D/custom_attribute_proposal_yeah_another_one_163246.html
>
> Inspired by a gallon of coffee, I decided to get it implemented. It's simple, based on what D already does (CTFE

["*drool*", "totally perfect awesomeness"] Thanks!

November 06, 2012
Wow, that's a surprise! Just yesterday I was thinking that it would be really nice to have them for a piece of code ;)

But shouldn't we keep the syntax closer to normal attributes and other languages(*)? I see a lot of arguments for doing that, with the only counter-argument that they would be in the same namespace as the built-in attributes (which should not be that bad, as this is very low level language stuff).

(*) i.e. @mytype or @("string") and without the '[]'
November 06, 2012
On 11/6/2012 12:15 AM, Tove wrote:
> ["*drool*", "totally perfect awesomeness"] Thanks!


The neato thing is I realized I could just connect the dots on what D already does well - CTFE, tuples, and templates. The actual features can now be added by library routines.
November 06, 2012
On 11/6/2012 12:20 AM, Sönke Ludwig wrote:> But shouldn't we keep the syntax closer to normal attributes and other
> languages(*)? I see a lot of arguments for doing that, with the only
> counter-argument that they would be in the same namespace as the
> built-in attributes (which should not be that bad, as this is very low
> level language stuff).
>
> (*) i.e. @mytype or @("string") and without the '[]'


We can debate the syntax. I don't have a store set by this one. I was more interested in getting the semantics right. Anyhow, it's nice to have a working prototype to experiment with rather than a paper airplane.
November 06, 2012
On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:
> -snip-

It doesn't look like it would be possible to schedule any runtime code using this, meaning they're not usable for stuff like registering types for serialization support, or doing runtime linking when attached to a function pointer, etc.

Even with user defined types or functions used in the attribute, the type or function itself doesn't know anything about the symbol it is being attached to, so it's quite limited what it can do.

Compared to other prevalent UDA systems, like C#'s, I'd say that this one is extremely limiting due to the two above points.

I'd love to hear some examples of what this particular take on UDAs allows in D, though.

November 06, 2012
On 11/6/2012 12:39 AM, Jakob Ovrum wrote:> On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:
>> -snip-
>
> It doesn't look like it would be possible to schedule any runtime code using
> this, meaning they're not usable for stuff like registering types for
> serialization support, or doing runtime linking when attached to a function
> pointer, etc.

Since D allows one to inquire and get a list of symbols, one can then iterate over them at compile time to determine which are serializable (or have some other specific attribute).

November 06, 2012
On Tuesday, 6 November 2012 at 08:42:44 UTC, Walter Bright wrote:
> Since D allows one to inquire and get a list of symbols, one can then iterate over them at compile time to determine which are serializable (or have some other specific attribute).

Yes, but somewhere you have to put startup code pointing in the general direction of where the attributes are used (like a module), it's not automatic. A static constructor cannot be used because it has no idea where to look.

But, I yield until someone comes up with actual examples of how these UDAs are useful, because I can't think of anything interesting at the moment. I guess I should go read over the old discussions you linked (I remember participating, but can't remember any specifics).


November 06, 2012
On Tuesday, 6 November 2012 at 07:55:51 UTC, Walter Bright wrote:
> snip

Nice to hear because it was unexpected and was requested prevously by community.
November 06, 2012
On 11/6/2012 12:42 AM, Walter Bright wrote:
> Since D allows one to inquire and get a list of symbols, one can then iterate
> over them at compile time to determine which are serializable (or have some
> other specific attribute).


To emphasize, the User Defined Attributes thing is completely a compile time feature. However, a user defined runtime system can be built on top of it.

It gives the best of both worlds.

« First   ‹ Prev
1 2 3 4 5 6 7 8 9 10 11
Top | Discussion index | About this forum | D home