November 29, 2017
On Wednesday, 29 November 2017 at 16:45:04 UTC, Timon Gehr wrote:
> On 29.11.2017 17:21, Andrei Alexandrescu wrote:
>> On 11/29/2017 07:53 AM, Seb wrote:
>>> UDAs for function arguments would be really awesome to have.
>> 
>> They should be part of the same DIP. -- Andrei
>
> More generally, any declaration should ideally support UDAs.
>
> One issue with UDAs on function arguments is that function types will then have embedded UDAs, so the DIP should specify how that works.

You have much more experience in how compilers work on the implementation level than me. What semantics are possible?

It makes sense to me that UDAs on function arguments should only be for documentation/reflection purposes. Therefore:

int fun(@Nonnull Object o);

Is considered to be equivalent to:

int fun(Object o);

And similarly:

import std.traits;
Parameters!fun -> (Object), not (@Nonnull Object)

However:

int fun(@Nonnull Object o)
{
    static if (is(typeof(fun) Params == __parameters))
    {
        static foreach (p; Params)
        {
            pragma(msg, __traits(getUDAs, p)); //Should print Nonnull
        }
    }
}

Unfortunately I don't think we can have both as that would mean that UDAs would have to be part of the function signature. Is there a way around this?
November 29, 2017
On 29.11.2017 17:58, Steven Schveighoffer wrote:
> On 11/29/17 11:45 AM, Timon Gehr wrote:
>> On 29.11.2017 17:21, Andrei Alexandrescu wrote:
>>> On 11/29/2017 07:53 AM, Seb wrote:
>>>> UDAs for function arguments would be really awesome to have.
>>>
>>> They should be part of the same DIP. -- Andrei
>>
>> More generally, any declaration should ideally support UDAs.
>>
>> One issue with UDAs on function arguments is that function types will then have embedded UDAs, so the DIP should specify how that works.
> 
> Wouldn't it work the same as this?
> 
> @("foo")
> struct S
> {
> 
> }
> 
> void main()
> {
>      import std.stdio;
>      @("bar") S s1;
>      S s2;
>      writeln(__traits(getAttributes, s1));         // bar
>      writeln(__traits(getAttributes, typeof(s1))); // foo
>      writeln(__traits(getAttributes, s2));         // (nothing)
>      writeln(__traits(getAttributes, typeof(s2))); // foo
> }
> 
> -Steve

I don't understand what you mean. Function types _contain_ parameter declarations. (Including attributes and default initializers.)
November 29, 2017
On 11/29/17 12:20 PM, Timon Gehr wrote:
> 
> I don't understand what you mean. Function types _contain_ parameter declarations. (Including attributes and default initializers.)

I too, am confused. I thought you meant that the types of the parameters would have attributes that might conflict/merge with the attributes declared on the parameters.

So maybe a snippet of code to further explain your concern?

-Steve
November 29, 2017
On 29.11.2017 19:18, Steven Schveighoffer wrote:
> On 11/29/17 12:20 PM, Timon Gehr wrote:
>>
>> I don't understand what you mean. Function types _contain_ parameter declarations. (Including attributes and default initializers.)
> 
> I too, am confused. I thought you meant that the types of the parameters would have attributes that might conflict/merge with the attributes declared on the parameters.
> 
> So maybe a snippet of code to further explain your concern?
> 
> -Steve

struct attribute1{}
struct attribute2{}

int foo(@attribute1 int x){ return x; }
int bar(@attribute2 int y){ return y; }

pragma(msg, typeof(&foo)); // int function(@attribute1 int x)?
pragam(msg, typeof(&bar)); // int function(@attribute2 int x)?

auto apply(F,A)(F fun,A arg){
    pragma(msg, F); // ? (instantiations below)
    return fun(arg);
}

void main(){
    apply(&foo,1); // one instantiation
    apply(&bar,1); // second instantiation, or same instance?
}

auto weird(){
    int x;
    void foo(@x int y){}
    return &foo;
}

pragma(msg, typeof(weird())); // ?
November 29, 2017
On 11/29/17 2:01 PM, Timon Gehr wrote:

OK, now I get what you are saying. In the same vein, I tested applying attributes to functions themselves:

@("a") int fun() { return 0; }
pragma(msg, typeof(&fun)); // int function()

@("b") int gun() { return 1; }
pragma(msg, typeof(&gun)); // int function()

void main()
{
  auto f = &fun;
  f = &gun; // works
}

Given that, it seems attributes play no part in the type itself, they are just metadata in the compiler.

I would say:

> 
> struct attribute1{}
> struct attribute2{}
> 
> int foo(@attribute1 int x){ return x; }
> int bar(@attribute2 int y){ return y; }
> 
> pragma(msg, typeof(&foo)); // int function(@attribute1 int x)?

int function(int)

> pragam(msg, typeof(&bar)); // int function(@attribute2 int x)?

same

> 
> auto apply(F,A)(F fun,A arg){
>      pragma(msg, F); // ? (instantiations below)

same

>      return fun(arg);
> }
> 
> void main(){
>      apply(&foo,1); // one instantiation
>      apply(&bar,1); // second instantiation, or same instance?

same instance

> }
> 
> auto weird(){
>      int x;
>      void foo(@x int y){}
>      return &foo;
> }
> 
> pragma(msg, typeof(weird())); // ?

void delegate(int)

-Steve
November 29, 2017
On 29.11.2017 20:49, Steven Schveighoffer wrote:
> On 11/29/17 2:01 PM, Timon Gehr wrote:
> 
> OK, now I get what you are saying. In the same vein, I tested applying attributes to functions themselves:
> 
> @("a") int fun() { return 0; }
> pragma(msg, typeof(&fun)); // int function()
> 
> @("b") int gun() { return 1; }
> pragma(msg, typeof(&gun)); // int function()
> 
> void main()
> {
>    auto f = &fun;
>    f = &gun; // works
> }
> 
> Given that, it seems attributes play no part in the type itself, they are just metadata in the compiler.

Well, I think the case of UDAs on parameters is closer to:

struct S{
    @("a") int x1;
    @("b") int x2;
}

The attributes on x1 and x2 are indeed part of the type S, even if the attributes on S itself are not.

If we go with "UDAs on parameters are not part of the function type", how to you get the UDAs of the parameters of some function?
November 29, 2017
On Wednesday, 29 November 2017 at 21:46:51 UTC, Timon Gehr wrote:
> On 29.11.2017 20:49, Steven Schveighoffer wrote:
>> On 11/29/17 2:01 PM, Timon Gehr wrote:
>> 
>> OK, now I get what you are saying. In the same vein, I tested applying attributes to functions themselves:
>> 
>> @("a") int fun() { return 0; }
>> pragma(msg, typeof(&fun)); // int function()
>> 
>> @("b") int gun() { return 1; }
>> pragma(msg, typeof(&gun)); // int function()
>> 
>> void main()
>> {
>>    auto f = &fun;
>>    f = &gun; // works
>> }
>> 
>> Given that, it seems attributes play no part in the type itself, they are just metadata in the compiler.
>
> Well, I think the case of UDAs on parameters is closer to:
>
> struct S{
>     @("a") int x1;
>     @("b") int x2;
> }
>
> The attributes on x1 and x2 are indeed part of the type S, even if the attributes on S itself are not.
>
> If we go with "UDAs on parameters are not part of the function type", how to you get the UDAs of the parameters of some function?

The function would have to be passed directly to __traits() to get the UDA. If passed to a function, it would have to be via alias:

void func(@attr int param) { }

void test(alias f)()
{
    writeln(getParameterAttr!(f, 0)); // or however to implement getting the attribute
}

test!func(); // prints @attr
November 29, 2017
On 11/29/17 4:46 PM, Timon Gehr wrote:
> On 29.11.2017 20:49, Steven Schveighoffer wrote:
>> On 11/29/17 2:01 PM, Timon Gehr wrote:
>>
>> OK, now I get what you are saying. In the same vein, I tested applying attributes to functions themselves:
>>
>> @("a") int fun() { return 0; }
>> pragma(msg, typeof(&fun)); // int function()
>>
>> @("b") int gun() { return 1; }
>> pragma(msg, typeof(&gun)); // int function()
>>
>> void main()
>> {
>>    auto f = &fun;
>>    f = &gun; // works
>> }
>>
>> Given that, it seems attributes play no part in the type itself, they are just metadata in the compiler.
> 
> Well, I think the case of UDAs on parameters is closer to:
> 
> struct S{
>      @("a") int x1;
>      @("b") int x2;
> }
> 
> The attributes on x1 and x2 are indeed part of the type S, even if the attributes on S itself are not.

Right, but unlike functions, you can't make another "overload" of a struct.

> 
> If we go with "UDAs on parameters are not part of the function type", how to you get the UDAs of the parameters of some function?

Looking at std.traits, it looks like we use this mechanism to get everything:

int func(int param1)

static if(is(typeof(func) F == __parameters))
{
    static assert(is(typeof(F[0]) == int));
    static assert(__traits(identifier, F[0]) == "param1");
}

This is how vibe.d associates the function-level attributes with the name of the parameter.

It wouldn't be a giant leap to make this work with attributes as well.

-Steve
November 30, 2017
On 30.11.2017 00:23, Steven Schveighoffer wrote:
> On 11/29/17 4:46 PM, Timon Gehr wrote:
>> On 29.11.2017 20:49, Steven Schveighoffer wrote:
>>> On 11/29/17 2:01 PM, Timon Gehr wrote:
>>>
>>> OK, now I get what you are saying. In the same vein, I tested applying attributes to functions themselves:
>>>
>>> @("a") int fun() { return 0; }
>>> pragma(msg, typeof(&fun)); // int function()
>>>
>>> @("b") int gun() { return 1; }
>>> pragma(msg, typeof(&gun)); // int function()
>>>
>>> void main()
>>> {
>>>    auto f = &fun;
>>>    f = &gun; // works
>>> }
>>>
>>> Given that, it seems attributes play no part in the type itself, they are just metadata in the compiler.
>>
>> Well, I think the case of UDAs on parameters is closer to:
>>
>> struct S{
>>      @("a") int x1;
>>      @("b") int x2;
>> }
>>
>> The attributes on x1 and x2 are indeed part of the type S, even if the attributes on S itself are not.
> 
> Right, but unlike functions, you can't make another "overload" of a struct.
> ...

You also cannot make another overload of a function type.

>>
>> If we go with "UDAs on parameters are not part of the function type", how to you get the UDAs of the parameters of some function?
> 
> Looking at std.traits, it looks like we use this mechanism to get everything:
> 
> int func(int param1)
> 
> static if(is(typeof(func) F == __parameters))
> {
>      static assert(is(typeof(F[0]) == int));
>      static assert(__traits(identifier, F[0]) == "param1");
> }
> 
> This is how vibe.d associates the function-level attributes with the name of the parameter.

This works because the name of the parameter is part of the function type. Default arguments are in there, too.

> ...
> It wouldn't be a giant leap to make this work with attributes as well.
> 
> -Steve

How will this work if typeof(func) does not contain the attributes?

November 30, 2017
On 29.11.2017 20:49, Steven Schveighoffer wrote:
> 
> I would say:
> 
>>
>> struct attribute1{}
>> struct attribute2{}
>>
>> int foo(@attribute1 int x){ return x; }
>> int bar(@attribute2 int y){ return y; }
>>
>> pragma(msg, typeof(&foo)); // int function(@attribute1 int x)?
> 
> int function(int)
> ...

Your suggestion is missing the parameter name.

>  ...
>>
>> auto weird(){
>>      int x;
>>      void foo(@x int y){}
>>      return &foo;
>> }
>>
>> pragma(msg, typeof(weird())); // ?
> 
> void delegate(int)
> 
> -Steve

Just noticed this:

auto weird(){
     int x=3;
     int foo(int y=x){ return y; }
     return &foo;
}
pragma(msg, typeof(weird)); // int delegate(int y = x)

I.e., we have "Voldemort initializers".