February 17, 2019
On Sunday, 17 February 2019 at 17:58:56 UTC, Rubn wrote:
> On Sunday, 17 February 2019 at 17:09:57 UTC, Yuxuan Shui wrote:
>> On Sunday, 17 February 2019 at 13:12:11 UTC, Rubn wrote:
>>> [...]
>>
>> This is allowed, _right now_. This is not an addition made by this DIP. Example: https://d.godbolt.org/z/hbwsaU
>
> Yes that's very different from what you want to implement it. See below.
>
>>> [...]
>>
>> And they have the problem that the name of the parameter becomes part of the API. This is something this DIP tries to solve.
>>
>>> [...]
>>
>> I am pretty sure this DIP listed some major languages with this feature, and it also includes concrete examples.
>
> Yes and Python doesn't behave the way you are suggesting. Listing the languages that implement the feature but not how they implement it makes the argument weaker. You list Python but I would not say Python implements this feature the same way as you are suggesting it to be implemented. I'd use Python as an example against this DIP (as I have).
>
> Eg the DIP suggests this be valid code so long as it can be distinguished by at least one parameter.
>
>     @named:
>     int add(int a, int b) { ... }
>     int add(int c, int d) { ... }

This is not valid under this DIP.

Actually, this is allowed under current D too, as long as you don't call "add". With my DIP, the behavior is the same, when you call add, you will get an error because your call matches both function. Parameter name is not part of overload resolution, this is explicitly stated in the DIP.


February 17, 2019
After thinking about the feedback so far, I currently plan to make these changes to this DIP:

* For reordering: I want to step back from reordering. It was add as an after thought, and turns out to be way more involved than I expected, and it is really not part of my goal for this DIP.

* For @named: Since there exist templates like ParameterIdentiferTuple, it shouldn't be hard to write a template to automatically wrap non-@named functions to make them @named. So this really is not a problem.

  If you are not satisfied with this solution (let me know), I have another proposal: @named will still be part of this DIP, but if a function is not annotated with @named, you can still call it with named parameters. If the names mismatch, you get a warning instead of an error. This way, API developers can clearly state their intentions with @named, and don't have to take responsibilities for API breakage caused by parameter rename; OTOH, API users can still call functions with named parameters.
February 17, 2019
On Sunday, 17 February 2019 at 20:58:04 UTC, Yuxuan Shui wrote:
> On Sunday, 17 February 2019 at 17:58:56 UTC, Rubn wrote:
>> On Sunday, 17 February 2019 at 17:09:57 UTC, Yuxuan Shui wrote:
>>> On Sunday, 17 February 2019 at 13:12:11 UTC, Rubn wrote:
>>>> [...]
>>>
>>> This is allowed, _right now_. This is not an addition made by this DIP. Example: https://d.godbolt.org/z/hbwsaU
>>
>> Yes that's very different from what you want to implement it. See below.
>>
>>>> [...]
>>>
>>> And they have the problem that the name of the parameter becomes part of the API. This is something this DIP tries to solve.
>>>
>>>> [...]
>>>
>>> I am pretty sure this DIP listed some major languages with this feature, and it also includes concrete examples.
>>
>> Yes and Python doesn't behave the way you are suggesting. Listing the languages that implement the feature but not how they implement it makes the argument weaker. You list Python but I would not say Python implements this feature the same way as you are suggesting it to be implemented. I'd use Python as an example against this DIP (as I have).
>>
>> Eg the DIP suggests this be valid code so long as it can be distinguished by at least one parameter.
>>
>>     @named:
>>     int add(int a, int b) { ... }
>>     int add(int c, int d) { ... }
>
> This is not valid under this DIP.
>
> Actually, this is allowed under current D too, as long as you don't call "add". With my DIP, the behavior is the same, when you call add, you will get an error because your call matches both function. Parameter name is not part of overload resolution, this is explicitly stated in the DIP.

How does it decide which function to call in this case, straight from the DIP, go through the entire process cause the DIP is rather ambiguous. Specifically if parameter names are not included in the mangled name of a function per the feature not being part of the scope of the DIP.

> int add(int a, int b) {...}
> int add(int c, int d) {...} // not in the overload set
> void main() {
>     add(a: 1, b: 2);
> }
>
> It might be useful to have parameter names included in the mangled name of a function so that changing the ordering of parameters does not break existing binaries. Such is beyond the scope of this DIP. A future DIP may address this issue.


February 18, 2019
On Sunday, 17 February 2019 at 21:04:23 UTC, Yuxuan Shui wrote:
> After thinking about the feedback so far, I currently plan to make these changes to this DIP:
>
> * For reordering: I want to step back from reordering. It was add as an after thought, and turns out to be way more involved than I expected, and it is really not part of my goal for this DIP.
>
> * For @named: Since there exist templates like ParameterIdentiferTuple, it shouldn't be hard to write a template to automatically wrap non-@named functions to make them @named. So this really is not a problem.

It is an issue if you are concern about compile time cost and generating unwanted verbiage. Templates despite powerful have a cost associated with them.

-Alex


February 18, 2019
On Sunday, 17 February 2019 at 21:04:23 UTC, Yuxuan Shui wrote:
> After thinking about the feedback so far, I currently plan to make these changes to this DIP:
>
> * For reordering: I want to step back from reordering. It was add as an after thought, and turns out to be way more involved than I expected, and it is really not part of my goal for this DIP.
>
> * For @named: Since there exist templates like ParameterIdentiferTuple, it shouldn't be hard to write a template to automatically wrap non-@named functions to make them @named. So this really is not a problem.
>
>   If you are not satisfied with this solution (let me know), I have another proposal: @named will still be part of this DIP, but if a function is not annotated with @named, you can still call it with named parameters. If the names mismatch, you get a warning instead of an error. This way, API developers can clearly state their intentions with @named, and don't have to take responsibilities for API breakage caused by parameter rename; OTOH, API users can still call functions with named parameters.

How about this: simply adding the ability to name the argument when calling a function? Example:

void rectangle(int width, int height) {}

void main()
{
    rectangle(1, 2);
    rectangle(width: 1, height: 2);
    rectangle(height: 2, width: 1);
    rectangle(width: 1, 2);    // error
}

All 3 function invocations lower to the same function call. Of course, naming should be either for all parameters or for none. This has the advantage that no code will be broken and naming will become optional. This way you have no mangling problems and you don't have to add any attributes.

This solution is also easier to implement and easier to drop/enhance after we gather some information about where we need to go with this.

Cheers
RazvanN
February 18, 2019
On Monday, 18 February 2019 at 08:32:02 UTC, RazvanN wrote:
> On Sunday, 17 February 2019 at 21:04:23 UTC, Yuxuan Shui wrote:
>> [...]
>
> How about this: simply adding the ability to name the argument when calling a function? Example:
>
> void rectangle(int width, int height) {}
>
> void main()
> {
>     rectangle(1, 2);
>     rectangle(width: 1, height: 2);
>     rectangle(height: 2, width: 1);
>     rectangle(width: 1, 2);    // error
> }
>
> All 3 function invocations lower to the same function call. Of course, naming should be either for all parameters or for none. This has the advantage that no code will be broken and naming will become optional. This way you have no mangling problems and you don't have to add any attributes.
>
> This solution is also easier to implement and easier to drop/enhance after we gather some information about where we need to go with this.
>
> Cheers
> RazvanN


I forgot to mention optional parameters; if there are any optional parameters and you are fine with the default value, you don't have to specify them.
February 18, 2019
On Friday, 15 February 2019 at 17:38:23 UTC, Francesco Mecca wrote:
> On Friday, 15 February 2019 at 13:49:04 UTC, Atila Neves wrote:
>> On Friday, 15 February 2019 at 12:56:45 UTC, Mike Parker wrote:
>>> [...]
>>
>> I'd add my library too as a possible library solution:
>>
>> https://github.com/atilaneves/kwargs
>
> I think that the solution proposed by Atila is better for the following reasons:
> 1. it is a library solution
> 2. allows both the user and the author of a library to specify functions with named parameters
> 3. it is very lightweight
>
> But it is not enough for the following reasons:
> 1. Works only on templates (I'd like someone to explain to me why)

That's not true - it works fine with regular functions.

> 2. Is opinionated about using ad-hoc types to represent data (the opposite of http://wiki.c2.com/?PrimitiveObsession)

Yes. I consider this to be a good thing, but then again, I would.
February 18, 2019
On Friday, 15 February 2019 at 17:43:52 UTC, 12345swordy wrote:
> On Friday, 15 February 2019 at 17:38:23 UTC, Francesco Mecca wrote:
>> On Friday, 15 February 2019 at 13:49:04 UTC, Atila Neves wrote:
>>> [...]
>>
>> I think that the solution proposed by Atila is better for the following reasons:
>> 1. it is a library solution
>> 2. allows both the user and the author of a library to specify functions with named parameters
>> 3. it is very lightweight
>>
>> [...]
>
> You miss the other reason on why it is not enough: Compile time and run-time performance penalty.
> -Alex

Run-time? I'd expect the call to inlined. It'll definitely take longer to compile though, but I'm at a loss why named parameters in the compiler are expected to be free.
February 18, 2019
On Friday, 15 February 2019 at 17:57:38 UTC, JN wrote:
> On Friday, 15 February 2019 at 17:43:52 UTC, 12345swordy wrote:
>>
>> You miss the other reason on why it is not enough: Compile time and run-time performance penalty.
>> -Alex
>
> Also, when doing a typo, rather than a nice error message "No named argument defined for function foo()", you'd probably get few screens of template vomit :)

Have you tried it? I attempted to static assert on nonsense with proper error messages. If you did and got terrible error messages, please file a github issue.
February 18, 2019
On Monday, 18 February 2019 at 10:17:32 UTC, Atila Neves wrote:
> On Friday, 15 February 2019 at 17:43:52 UTC, 12345swordy wrote:
>> On Friday, 15 February 2019 at 17:38:23 UTC, Francesco Mecca wrote:
>>> On Friday, 15 February 2019 at 13:49:04 UTC, Atila Neves wrote:
>>>> [...]
>>>
>>> I think that the solution proposed by Atila is better for the following reasons:
>>> 1. it is a library solution
>>> 2. allows both the user and the author of a library to specify functions with named parameters
>>> 3. it is very lightweight
>>>
>>> [...]
>>
>> You miss the other reason on why it is not enough: Compile time and run-time performance penalty.
>> -Alex
>
> Run-time? I'd expect the call to inlined. It'll definitely take longer to compile though, but I'm at a loss why named parameters in the compiler are expected to be free.

The compiler isn't some magic device, your implementation is not easily optimized out to have no runtime cost. Even LDC has trouble optimizing it, and forget about DMD.

struct Foo {
    int[1024] value;
}

void foo(ref Foo faa ) {
    import core.stdc.stdio : printf;
    foreach(int i, ref v; faa.value) {
        printf("%d", v);
    }
 }

alias slowFoo = kwargify!foo;

void func() {
    import std.stdio;
    Foo f;

    foreach(int i, ref v; f.value) {
        writeln("%d", v);
    }

    slowFoo( f );

    foreach(int i, ref v; f.value) {
        writeln("%d", v);
    }

}

void example.func():
        push    rbp
        push    r15
        push    r14
        push    rbx
        sub     rsp, 8200
        lea     rdi, [rsp + 4104]
        xor     ebx, ebx
        xor     esi, esi
        mov     edx, 4096
        call    memset@PLT
        lea     r15, [rsp + 8]
        lea     r14, [rip + .L.str.1]
.LBB1_1:
        mov     ebp, dword ptr [rsp + 4*rbx + 4104]
        mov     rdi, r15
        call    @property @trusted std.stdio.File std.stdio.trustedStdout()@PLT
        mov     esi, 10
        mov     ecx, 2
        mov     rdi, r15
        mov     edx, ebp
        mov     r8, r14
        call    @safe void std.stdio.File.write!(immutable(char)[], int, char).write(immutable(char)[], int, char)@PLT
        mov     rdi, r15
        call    @safe void std.stdio.File.__dtor()@PLT
        add     rbx, 1
        cmp     rbx, 1024
        jb      .LBB1_1
        lea     rdi, [rsp + 8]
        lea     rsi, [rsp + 4104]
        mov     edx, 4096
        call    memcpy@PLT          <--------------------
        lea     rbx, [rip + .L.str.1]
        xor     ebp, ebp
.LBB1_4:
        mov     esi, dword ptr [rsp + 4*rbp + 8]
        xor     eax, eax
        mov     rdi, rbx
        call    printf@PLT           <-------------------
        add     rbp, 1
        cmp     rbp, 1024
        jne     .LBB1_4
        xor     ebx, ebx
        lea     r15, [rsp + 8]
        lea     r14, [rip + .L.str.1]

https://godbolt.org/z/6Tu8V7

As you can it is unable to optimize the extra copy that your implementation does by having to build a tuple before passing it to the function.

No one is arguing that named parameters that are built in will be free. But it will be way faster as the compiler knows exactly what you are doing, not the hacky workaround you have that is severally limited (no templates, distinguished by types not "names" only allows you to reorder parameters all but useless for default types like int/float). Your implementation is extremely slow, both increasing compile times and decreasing runtime performance. All for the purpose of simply making code more readable. That's not a worthwhile trade off for the performance hit in both aspects.