Thread overview
Re: Template args to UDA's
May 28, 2013
Kenji Hara
May 28, 2013
Johannes Pfau
May 28, 2013
Manu
May 28, 2013
Kenji Hara
May 31, 2013
Timon Gehr
May 31, 2013
Manu
May 31, 2013
Manu
Jun 01, 2013
Timon Gehr
May 29, 2013
Manu
May 28, 2013
2013/5/28 Manu <turkeyman@gmail.com>

> So I've run into an expression I need to be able to implement std.simd properly for GDC/LDC.
>
> Doesn't work:
>   @attribute("target", T) void func(string T)(...);
>
> In this case, currently, the UDA can't receive the template arg that was given to the function.
>
> I require that attributes on templates be able to make use of the template args, since the template arg given may affect the attribute in some circumstances.
>

This code works.

string attribute(string, string s) { return s; }

//@attribute("target", T) void func(string T)() {}
template func(string T)
{
    @attribute("target", T) void func() {}
}

void main()
{
    alias f1 = func!"a";
    alias f2 = func!"b";
    pragma(msg, __traits(getAttributes, f1));   // "a"
    pragma(msg, __traits(getAttributes, f2));   // "b"
    f1();
    f2();
}

Kenji Hara


May 28, 2013
Indeed it does.
It's a bit obtuse though having to wrap my function up in an outer template
just to scope the template arg correctly.

Do you think it's reasonable that an attribute should be scoped such that
it can see the template args of the declaration it's bound to?
It kinda makes sense, an attribute is intrinsically connected to the
declaration, so it should be able to access any template args given...


On 28 May 2013 23:51, Kenji Hara <k.hara.pg@gmail.com> wrote:

> 2013/5/28 Manu <turkeyman@gmail.com>
>
>> So I've run into an expression I need to be able to implement std.simd properly for GDC/LDC.
>>
>> Doesn't work:
>>   @attribute("target", T) void func(string T)(...);
>>
>> In this case, currently, the UDA can't receive the template arg that was given to the function.
>>
>> I require that attributes on templates be able to make use of the template args, since the template arg given may affect the attribute in some circumstances.
>>
>
> This code works.
>
> string attribute(string, string s) { return s; }
>
> //@attribute("target", T) void func(string T)() {}
> template func(string T)
> {
>     @attribute("target", T) void func() {}
> }
>
> void main()
> {
>     alias f1 = func!"a";
>     alias f2 = func!"b";
>     pragma(msg, __traits(getAttributes, f1));   // "a"
>     pragma(msg, __traits(getAttributes, f2));   // "b"
>     f1();
>     f2();
> }
>
> Kenji Hara
>


May 28, 2013
It looks reasonable, but in general case it would introduce not trivial semantic issue.

Based on the current D language spec, prefix attribute is just rewritten to blocked attribute.

@attribute("target", T) void func(string T)() {}

to:
@attribute("target", T) {
    void func(string T)() {}
}

And block attribute can contain other declarations.

@attribute("target", T) {

    enum str = T.stringof;

    void func(string T)() {}
}

Well, if the enhancement is implemented, T would be deduced by the each call of template function foo. Then the enum value would become undeterministic.

I think it is not implementable.

Kenji Hara


2013/5/28 Manu <turkeyman@gmail.com>

> Indeed it does.
> It's a bit obtuse though having to wrap my function up in an outer
> template just to scope the template arg correctly.
>
> Do you think it's reasonable that an attribute should be scoped such that
> it can see the template args of the declaration it's bound to?
> It kinda makes sense, an attribute is intrinsically connected to the
> declaration, so it should be able to access any template args given...
>
>
> On 28 May 2013 23:51, Kenji Hara <k.hara.pg@gmail.com> wrote:
>
>> 2013/5/28 Manu <turkeyman@gmail.com>
>>
>>> So I've run into an expression I need to be able to implement std.simd properly for GDC/LDC.
>>>
>>> Doesn't work:
>>>   @attribute("target", T) void func(string T)(...);
>>>
>>> In this case, currently, the UDA can't receive the template arg that was given to the function.
>>>
>>> I require that attributes on templates be able to make use of the template args, since the template arg given may affect the attribute in some circumstances.
>>>
>>
>> This code works.
>>
>> string attribute(string, string s) { return s; }
>>
>> //@attribute("target", T) void func(string T)() {}
>> template func(string T)
>> {
>>     @attribute("target", T) void func() {}
>> }
>>
>> void main()
>> {
>>     alias f1 = func!"a";
>>     alias f2 = func!"b";
>>     pragma(msg, __traits(getAttributes, f1));   // "a"
>>     pragma(msg, __traits(getAttributes, f2));   // "b"
>>     f1();
>>     f2();
>> }
>>
>> Kenji Hara
>>
>
>


May 28, 2013
Am Tue, 28 May 2013 22:51:29 +0900
schrieb Kenji Hara <k.hara.pg@gmail.com>:

> 2013/5/28 Manu <turkeyman@gmail.com>
> 
> 
> This code works.
> 

Interesting. I tried that as well but used writeln to print the output:

writeln(__traits(getAttributes, func!"a")); //Fails
enum result = __traits(getAttributes, func!"a");
writeln(result); //works

Is this a known bug?
May 29, 2013
On 29 May 2013 01:45, Kenji Hara <k.hara.pg@gmail.com> wrote:

> It looks reasonable, but in general case it would introduce not trivial semantic issue.
>
> Based on the current D language spec, prefix attribute is just rewritten to blocked attribute.
>
> @attribute("target", T) void func(string T)() {}
>
> to:
> @attribute("target", T) {
>     void func(string T)() {}
> }
>
> And block attribute can contain other declarations.
>
> @attribute("target", T) {
>
>     enum str = T.stringof;
>
>     void func(string T)() {}
> }
>
> Well, if the enhancement is implemented, T would be deduced by the each call of template function foo. Then the enum value would become undeterministic.
>
> I think it is not implementable.
>

Well, until now, the lowering of an attribute to a scoped attribute would
have always worked seamlessly, since no hard attributes ever received
arguments.
I'd suggest that it may no longer be reasonable behaviour to lower an
attribute to a scoped attribute.

@attribute("target", T) void func(string T)() {}
@attribute("target", T) { ...stuff... void func(string T)() {} ...stuff... }

The 2 cases are quite distinct.
In the first, it looks very much like the the attribute is attributing the
declaration (it really is PART of the declaration), and as such, should
have access to any arguments supplied to the declaration.
In the second case, it's quite clear that there is an outer scope. Any
reasonably programmer will expect that parameters to an inner declaration
will not be available in the outer scope.

The issue seems to be an implementation detail, which was based on a premise that's no longer strictly true.

Kenji Hara
>
>
> 2013/5/28 Manu <turkeyman@gmail.com>
>
>> Indeed it does.
>> It's a bit obtuse though having to wrap my function up in an outer
>> template just to scope the template arg correctly.
>>
>> Do you think it's reasonable that an attribute should be scoped such that
>> it can see the template args of the declaration it's bound to?
>> It kinda makes sense, an attribute is intrinsically connected to the
>> declaration, so it should be able to access any template args given...
>>
>>
>> On 28 May 2013 23:51, Kenji Hara <k.hara.pg@gmail.com> wrote:
>>
>>> 2013/5/28 Manu <turkeyman@gmail.com>
>>>
>>>> So I've run into an expression I need to be able to implement std.simd properly for GDC/LDC.
>>>>
>>>> Doesn't work:
>>>>   @attribute("target", T) void func(string T)(...);
>>>>
>>>> In this case, currently, the UDA can't receive the template arg that was given to the function.
>>>>
>>>> I require that attributes on templates be able to make use of the template args, since the template arg given may affect the attribute in some circumstances.
>>>>
>>>
>>> This code works.
>>>
>>> string attribute(string, string s) { return s; }
>>>
>>> //@attribute("target", T) void func(string T)() {}
>>> template func(string T)
>>> {
>>>     @attribute("target", T) void func() {}
>>> }
>>>
>>> void main()
>>> {
>>>     alias f1 = func!"a";
>>>     alias f2 = func!"b";
>>>     pragma(msg, __traits(getAttributes, f1));   // "a"
>>>     pragma(msg, __traits(getAttributes, f2));   // "b"
>>>     f1();
>>>     f2();
>>> }
>>>
>>> Kenji Hara
>>>
>>
>>
>


May 31, 2013
On 05/28/2013 05:45 PM, Kenji Hara wrote:
> It looks reasonable, but in general case it would introduce not trivial
> semantic issue.
>
> Based on the current D language spec, prefix attribute is just rewritten
> to blocked attribute.
>
> @attribute("target", T) void func(string T)() {}
>
> to:
> @attribute("target", T) {
>      void func(string T)() {}
> }
>

It is my understanding as well, but where is this actually specified?

> And block attribute can contain other declarations.
>
> @attribute("target", T) {
>
>      enum str = T.stringof;
>
>      void func(string T)() {}
> }
>
> Well, if the enhancement is implemented, T would be deduced by the each
> call of template function foo. Then the enum value would become
> undeterministic.
>
> I think it is not implementable.
> ...


This does not follow.

@attribute("target", T) void func(string T)() {}

would simply need to be treated like:

template func(string T){
    @attribute("target", T) void func() {}
}

(The same would then be done for other attributes.)

I think it makes a difference only for UDA's and pragmas.
May 31, 2013
On 31 May 2013 20:47, Timon Gehr <timon.gehr@gmx.ch> wrote:

> On 05/28/2013 05:45 PM, Kenji Hara wrote:
>
>> It looks reasonable, but in general case it would introduce not trivial semantic issue.
>>
>> Based on the current D language spec, prefix attribute is just rewritten to blocked attribute.
>>
>> @attribute("target", T) void func(string T)() {}
>>
>> to:
>> @attribute("target", T) {
>>      void func(string T)() {}
>> }
>>
>>
> It is my understanding as well, but where is this actually specified?
>
>  And block attribute can contain other declarations.
>>
>> @attribute("target", T) {
>>
>>      enum str = T.stringof;
>>
>>      void func(string T)() {}
>> }
>>
>> Well, if the enhancement is implemented, T would be deduced by the each call of template function foo. Then the enum value would become undeterministic.
>>
>> I think it is not implementable.
>> ...
>>
>
>
> This does not follow.
>
> @attribute("target", T) void func(string T)() {}
>
> would simply need to be treated like:
>
>
> template func(string T){
>     @attribute("target", T) void func() {}
> }
>
> (The same would then be done for other attributes.)
>
> I think it makes a difference only for UDA's and pragmas.
>

Or fully expanded:

template func(string T) {
  @attribute("target", T) {
    void func() { }
  }
}

This seems to fix the existing semantics rather nicely.


May 31, 2013
* fix = fit


On 31 May 2013 20:56, Manu <turkeyman@gmail.com> wrote:

> On 31 May 2013 20:47, Timon Gehr <timon.gehr@gmx.ch> wrote:
>
>> On 05/28/2013 05:45 PM, Kenji Hara wrote:
>>
>>> It looks reasonable, but in general case it would introduce not trivial semantic issue.
>>>
>>> Based on the current D language spec, prefix attribute is just rewritten to blocked attribute.
>>>
>>> @attribute("target", T) void func(string T)() {}
>>>
>>> to:
>>> @attribute("target", T) {
>>>      void func(string T)() {}
>>> }
>>>
>>>
>> It is my understanding as well, but where is this actually specified?
>>
>>  And block attribute can contain other declarations.
>>>
>>> @attribute("target", T) {
>>>
>>>      enum str = T.stringof;
>>>
>>>      void func(string T)() {}
>>> }
>>>
>>> Well, if the enhancement is implemented, T would be deduced by the each call of template function foo. Then the enum value would become undeterministic.
>>>
>>> I think it is not implementable.
>>> ...
>>>
>>
>>
>> This does not follow.
>>
>> @attribute("target", T) void func(string T)() {}
>>
>> would simply need to be treated like:
>>
>>
>> template func(string T){
>>     @attribute("target", T) void func() {}
>> }
>>
>> (The same would then be done for other attributes.)
>>
>> I think it makes a difference only for UDA's and pragmas.
>>
>
> Or fully expanded:
>
> template func(string T) {
>   @attribute("target", T) {
>     void func() { }
>   }
> }
>
> This seems to fix the existing semantics rather nicely.
>


May 31, 2013
On Fri, 31 May 2013 06:47:07 -0400, Timon Gehr <timon.gehr@gmx.ch> wrote:

> @attribute("target", T) void func(string T)() {}
>
> would simply need to be treated like:
>
> template func(string T){
>      @attribute("target", T) void func() {}
> }

In fact, today's current semantics suggest this is exactly what happens:

import std.stdio;

@("a") void func(T)(T t) {}

void main()
{
    writefln("func attributes: %s", [__traits(getAttributes, func)]);
    writefln("func!int attributes: %s", [__traits(getAttributes, func!int)]);
}

Output:

func attributes: []
func!int attributes: ["a"]

If the attributes applied only to the template symbol, then you would think func would have the attribute a.

Plus, the idea that you must actually instantiate the template to get an attribute to apply REALLY suggests the attribute should be aware of the template parameters.

-Steve
June 01, 2013
On 05/31/2013 04:23 PM, Steven Schveighoffer wrote:
> On Fri, 31 May 2013 06:47:07 -0400, Timon Gehr <timon.gehr@gmx.ch> wrote:
>
>> @attribute("target", T) void func(string T)() {}
>>
>> would simply need to be treated like:
>>
>> template func(string T){
>>      @attribute("target", T) void func() {}
>> }
>
> In fact, today's current semantics suggest this is exactly what happens:
>

It is not what happens (otherwise Manu's initial code would work), but you obviously have a point.

> import std.stdio;
>
> @("a") void func(T)(T t) {}
>
> void main()
> {
>      writefln("func attributes: %s", [__traits(getAttributes, func)]);
>      writefln("func!int attributes: %s", [__traits(getAttributes,
> func!int)]);
> }
>
> Output:
>
> func attributes: []
> func!int attributes: ["a"]
>
> If the attributes applied only to the template symbol, then you would
> think func would have the attribute a.
>
> Plus, the idea that you must actually instantiate the template to get an
> attribute to apply REALLY suggests the attribute should be aware of the
> template parameters.
>
> -Steve

Agreed.