November 06, 2012
Am Tue, 06 Nov 2012 09:49:42 +0100
schrieb "Jakob Ovrum" <jakobovrum@gmail.com>:

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

The std.benchmark proposal currently requires all benchmark functions to be named "benchmark_name":

void benchmark_stdio_write_test() {}

with UDA:

@benchmark("stdio write test") void benchStdioWrite();

Of course you still need that "sheduleBenchmarks" mixin in every module and of course it'd be nice to avoid that. But UDAs are already a big step forward.
November 06, 2012
On 11/6/2012 7:55 AM, Jacob Carlborg wrote:
> On 2012-11-06 16:39, Walter Bright wrote:
>> On 11/6/2012 5:04 AM, Jacob Carlborg wrote:
>>> I agree, I a syntax like this would have been nicer:
>>>
>>> @mtype("key" : "value") int a; or @mtype(key : "value") int a;
>>> @mtype("value") int b;
>>> @mtype int c;
>>>
>>
>> Part of what I was trying to do was minimizing inventing new syntaxes. The
>>
>>     [ ArgumentList ]
>>
>> invents nothing new but the brackets. Your proposal is both a new
>> syntax, and it can only do key/value pairs - nothing else.
>
> It depends on how you look at it.
>
> * @mtype - is the same syntax as the current syntax for attributes
> * @mtype("key" : "value") - Uses the above in combination with the syntax for
> associative array literals
>
> How about this then:
>
> @mtype("foo", 3, "bar") int a;
>
> And have the argument list be optional? I really like to have a short nice
> looking syntax for the simple use cases, i.e.
>
> @mtype int b;
>

There's a lot more you can do with the ArgumentList syntax than associative arrays. Furthermore, there remains the problem of how mtype fits into the name scoping system.
November 06, 2012
On 11/6/2012 8:04 AM, Johannes Pfau wrote:> The std.benchmark proposal currently requires all benchmark functions to
> be named "benchmark_name":
>
> void benchmark_stdio_write_test() {}
>
> with UDA:
>
> @benchmark("stdio write test") void benchStdioWrite();
>
> Of course you still need that "sheduleBenchmarks" mixin in every module
> and of course it'd be nice to avoid that. But UDAs are already a big
> step forward.
>

Consider that you can use a tuple generated elsewhere for a UDA:

[tp] void foo();

where tp is a tuple. You can even grab the attributes from another symbol, turn them into a tuple, and apply the tuple as an attribute to a new symbol. Tuples can, of course, be sliced and concatenated.

In other words, by using tuples, you can "encapsulate" what the attributes expand to in the same way you can change target code by changing the definition of user defined types.
November 06, 2012
For the syntax maybe it's better something like @() instead of [], so it becomes more greppable and more easy to tell apart visually from the array literals:

@(1, "xx", Foo) int x;


Supporting annotations for function arguments is probably an important sub-feature.

Yesterday I was discussing about the bug-prone nature of foreach loops on a struct array, and one of the solutions I've suggested was a user-defined annotation for the programmer to denote that she wants to modify just the copy:

struct Foo {}
Foo[10] foos;
foreach (@copy f; foos) { ... }

With UDA syntax:

foreach ([Copy] f; foos) { ... }
Or:
foreach (@(Copy) f; foos) { ... }

But I think there's no way to tell the compiler to give a compile-time error if such annotation is not present there (unless there's "ref").

---------------------

Gor Gyolchanyan:

> @flags enum A { ... }
>
> the "flags" attribute would replace the declaraction of A with another enum declaration with the same name and same members, but with replaced initialization and would static assert(false, "flags enum can't have initializers") if any initializers are given.

I appreciate your idea (I think of user-defined attributes also as ways to extend the type system), But I know the engineer in Walter prefers extra-simple ideas, so maybe your idea will not be accepted :-) But let's see.

Bye,
bearophile
November 06, 2012
On 11/6/2012 8:02 AM, Tove wrote:
> On Tuesday, 6 November 2012 at 15:19:53 UTC, Walter Bright wrote:
>> On 11/6/2012 7:14 AM, Tove wrote:
>>> Hmmm, actually it doesn't work in plain function/block scope either.
>>
>> Right, I don't see a compelling purpose for that, either.
>
> Hmm, what about library based GC annotations?
>
> ["GC.NoScan"] int* local_p;
>

I have no idea how you could make that work.
November 06, 2012
Le 06/11/2012 08:55, Walter Bright a écrit :
> 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.

OK, I may break all the happiness of that news but . . .

Tuple in D is notoriously known to be a badly designed feature. Basing more stuff on that just because we have them is short sighted and will only result in D's tuples being broken forever, several tuples implementations for more user confusion, or future major breakage.

We still don't have any scheme for a stable D, feature testing or whatever, so everybody should be prepared for many new ICE (or even more fun, bugs). After we all love them or we wouldn't be using D ! Who need a programming language to be stable or reliable ?

Surprise feature ! Yaw, no wonder D's toolchain is so wonderfull ! Let's not talk these awesome static code analysis tools, java would become jealous.

BTW, I don't really like that syntax, but really, that isn't important.
November 06, 2012
Le 06/11/2012 09:20, Sönke Ludwig a écrit :
> 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 '[]'

+1

In addition, this is [] thing will require lookahead when parsing to detect if we have an expression (array literal) or a declaration.
November 06, 2012
On 11/6/2012 8:29 AM, deadalnix wrote:
> In addition, this is [] thing will require lookahead when parsing to detect if
> we have an expression (array literal) or a declaration.

Not really, as an array literal starting an expression is kinda meaningless,
like:

   a*b;

is a declaration, not a multiply.
November 06, 2012
Le 06/11/2012 10:07, Walter Bright a écrit :
> n 11/6/2012 12:59 AM, Jakob Ovrum wrote:
>  > Problem is that there's no way to do this without having the user
> specify which
>  > modules it should work for, like:
>  >
>  > import attributes;
>  > import a, b, c;
>  >
>  > static this() // This code cannot be automated.
>  > {
>  > initAttributes!a();
>  > initAttributes!b();
>  > initAttributes!c();
>  > }
>  >
>
> Is that really a problem?

I'm not sure. How can AOP be implemented on top of that ?
November 06, 2012
On 11/6/2012 8:23 AM, bearophile wrote:
> Supporting annotations for function arguments is probably an important sub-feature.

It would be a significant extension, and so I'd like to see a compelling use case first.


> Yesterday I was discussing about the bug-prone nature of foreach loops on a
> struct array, and one of the solutions I've suggested was a user-defined
> annotation for the programmer to denote that she wants to modify just the copy:
>
> struct Foo {}
> Foo[10] foos;
> foreach (@copy f; foos) { ... }
>
> With UDA syntax:
>
> foreach ([Copy] f; foos) { ... }
> Or:
> foreach (@(Copy) f; foos) { ... }
>
> But I think there's no way to tell the compiler to give a compile-time error if
> such annotation is not present there (unless there's "ref").

User defined attributes cannot invent new semantics for the language. And besides, 'ref' already does what you suggest.