February 15, 2019
Am 15.02.19 um 13:56 schrieb Mike Parker:
> [...]

All in all, DIP 1019 looks quite interesting and also primising to me. I do however see some issues with the DIP:

1. The rationale describes 2 problems that can arise when not having named arguments, but it does not describe how those problems could be prevented by using named arguments.

2. In the "Description" secion, the DIP says:

> When the label and the corresponding parameter name mismatch, the
compiler will generate an error of the following nature: "Named argument 'foo' does not match function parameter name 'bar'."

I don't really understand how the compiler should generate this exact error message. How can the compiler know that the argument passed with name 'foo' is supposed to match the actual parameter 'bar'? I don't think this is possible if reordering of named arguments is allowed (as the DIP later suggests).

To clearify this, the DIP should provide code examples where those mismatches occur and what errors are detected (or not bother with specifying what the exact error message is, but simply state that this is a compile error, but also provide examples).

3. In the completeness section, I would have liked an example to make this more easily understandable.

4. In the "Alternatives" section, the DIP says:

> For example, in one potential library-only solution, it is necessary
to call functions like so:
>
> args!(add, a=>1, b=>1);
>
> This has too much noise and, moreover, does not allow for the use of
Uniform Function Call Syntax (UFCS).

This clearly suggests that named arguments as proposed by the DIP should work with UFCS. However, the DIP fails to explain how this should actually work. At the moment, UFCS works by lowering as described in the following example:

```d
int add(int a, int b, int c) { /* ... */ }

void main() {
    1.add(2, 3); // lowered to add(1, 2, 3);
}
```

It is totally unclear how this should work with named arguments.

5. Similarly, as already mentioned by somebody else, the DIP fails to explain interaction with function default arguments.

6. Another possible interaction the DIP does not mention at all is implicit istanciation of template functions. Without giving it too much tought, to me it looks like this should actually work. But the DIP does not consider this at all. It should at least describe whether those features are compatible or not, and provide examples if they are.

February 15, 2019
On Friday, 15 February 2019 at 17:03:40 UTC, aliak wrote:
> On Friday, 15 February 2019 at 12:56:45 UTC, Mike Parker wrote:
>> This is the feedback thread for the first round of Community Review for DIP 1019, "Named Arguments Lite":
>
> Wee! Named arguments :D
>
> There's also another solution that was brought up by Simen.
>
> Forum post: https://forum.dlang.org/post/ejnsqqebrjbwefjhagvg@forum.dlang.org
> An implementation: https://github.com/aliak00/ddash/commit/911e3b580e7bbe06f43c258a2d1c78f97a9668c5#diff-6919882fdb1af168f0e5b90603414fae
>
> Basically we have the following decision dimensions when allowing named parameters in APIs
>
> Also I'm on the side of named parameters being the default and the API author deciding if their use is opt-out. But, that's a compile time breaking change to, basically, everything. So I guess that's out the window. So, there's probably a better chance with named parameters being opt-in.

Yes, one of my "design goal" is to maximize my chance :)

>
> 1) I don't think it should be re-orderable because it allows callers to abuse APIs and not be used how the author (may have) intended:
>
> void call(int me, int maybe) {}
>
> call(maybe: 3, me: 2);
> call(me: 2, maybe: 3);
>
> Carly Ray would roll in her grave :p Also, who's calling who?!?

I was reluctant about add reordering too. The first version of the proposal doesn't have reordering. But after some thought, I realized reordering cannot be add as an extension of this proposal without breakage. So in order to not rule reordering out, I have to include that in the proposal.

But now I reconsider it again, it is probably not as bad as I thought. The future reordering proposal can probably *also* be opt-in behind a attribute. So I am not really decided at this moment.

>
> Also, it makes named overload resolution impossible should the need arise:
>
> void call(int a, int b) {}
> void call(int b, int a) {}
>
> call(a: 3, b: 4); // ??

This is a compile time error since the call matches both functions.

>
> 2) Then there's the issue of external names and internal names, as an API designer, I want to be able to specify an external name but also have a different internal identifier
>
> move(T)(T from, T to);
>
> Requires the awkward use of variables from and to in the function body. It's not the end of the world of course, but allowing external and internal variable naming gives allows for the best user experience, and code readability from both caller and API author:
>
> move(T)(T from source, T to dest) {
>   // implementation use source and dest
> }
>
> // caller uses from and to:
> move(from: x, to: y);

This can be done with this proposal, you do

    move(T)(T source, T dest) { /* code */ }
    @named move(T)(T from, T to);

>
> 3) Disallowing named arguments. In my experience this is especially useful for the first argument to a function.
>
> move(x, to: y);
>
> How does a ":" sound as an addition to the parameter list to be able to achieve all of these? By default, everything stays the same, i.e. no named parameters. If you add a ":" to your parameter then it *must* be called via named arguments by the caller. And if you have a second identifier after your first, then that one becomes the internal identifier (this can also be a separate DIP maybe in the future as it's additional)
>
> move(T)(T :from, T :to);
> move(a, b); // error
> move(from: a, to: b); // ok
>
> move(T)(T from, T :to);
> move(a, b); // error
> move(from: a, to: b); // error
> move(a, to: b); // ok
>
> Then there's the issue of default arguments:
> * A default argument on an unnamed parameter can only come at the end.
> * A default argument on a named parameter can go anywhere
>
> void func(int a = 3, int :b)
> func(b: 7); // ok
>
> void func(int a = 3, int b); // error
>
> void func(int :a = 7, int b, int :c = 4);
>
> func(3); // ok
>
> void func(int :a = 7, int b, int :c);
>
> func(3, c: 8);
>
> I think parameter lock in is as valid as a concern as function name lock in.

This proposal doesn't prevent your suggestion from being implemented in the future :)

>
> [snip]


February 15, 2019
On Friday, 15 February 2019 at 18:04:36 UTC, Johannes Loher wrote:
> Am 15.02.19 um 13:56 schrieb Mike Parker:
>> [...]
>
> All in all, DIP 1019 looks quite interesting and also primising to me. I do however see some issues with the DIP:
>
> 1. The rationale describes 2 problems that can arise when not having named arguments, but it does not describe how those problems could be prevented by using named arguments.
>
> 2. In the "Description" secion, the DIP says:
>
>> When the label and the corresponding parameter name mismatch, the
> compiler will generate an error of the following nature: "Named argument 'foo' does not match function parameter name 'bar'."
>
> I don't really understand how the compiler should generate this exact error message. How can the compiler know that the argument passed with name 'foo' is supposed to match the actual parameter 'bar'? I don't think this is possible if reordering of named arguments is allowed (as the DIP later suggests).
>
> To clearify this, the DIP should provide code examples where those mismatches occur and what errors are detected (or not bother with specifying what the exact error message is, but simply state that this is a compile error, but also provide examples).
>
> 3. In the completeness section, I would have liked an example to make this more easily understandable.
>
> 4. In the "Alternatives" section, the DIP says:
>
>> For example, in one potential library-only solution, it is necessary
> to call functions like so:
>>
>> args!(add, a=>1, b=>1);
>>
>> This has too much noise and, moreover, does not allow for the use of
> Uniform Function Call Syntax (UFCS).
>
> This clearly suggests that named arguments as proposed by the DIP should work with UFCS. However, the DIP fails to explain how this should actually work. At the moment, UFCS works by lowering as described in the following example:
>
> ```d
> int add(int a, int b, int c) { /* ... */ }
>
> void main() {
>     1.add(2, 3); // lowered to add(1, 2, 3);
> }
> ```
>
> It is totally unclear how this should work with named arguments.

Thanks for pointing these out, they will be fixed in the next revision.

>
> 5. Similarly, as already mentioned by somebody else, the DIP fails to explain interaction with function default arguments.

I think it is reasonable to require a prefix of the parameters are specified.

e.g. int fun(int a, int b = 1, int c = 2, int d = 3);

The user can specify (a), (a, b), (a, b, c) or all of the parameters, and the arguments can be in any order.

>
> 6. Another possible interaction the DIP does not mention at all is implicit instantiation of template functions. Without giving it too much thought, to me it looks like this should actually work. But the DIP does not consider this at all. It should at least describe whether those features are compatible or not, and provide examples if they are.

I think it should just work. But I would give it some thought and include that in the next revision.

Thanks!


February 15, 2019
On Friday, 15 February 2019 at 17:06:18 UTC, Jacob Shtokolov wrote:
> On Friday, 15 February 2019 at 12:56:45 UTC, Mike Parker wrote:
>> [...]
>
>
> I think the "Completeness" section contains some arguable points. The proposed solution doesn't take into account the cases where you need to partially skip default arguments.
>
> Say, we have a function:
>
> ```void drawCircle(int x, int y, int radius, Border border = Border.Solid, Bg bg = Bg.Transparent)```
>
> Then we want to call this function with default parameters except the background (bg).
>
> The best way to do that would be:
> ```drawCircle(10, 10, 5, bg: Bg.Red);```
>
> So you see that we omitted the "border" parameter.
>
> However, the proposed solution forces us to do that:
> ```drawCircle(x: 10, y: 10, radius: 5, bg: Bg.Red);```
>
> A lot more unnecessary typing.
>
> Python, for example, allows us to mix both named and unnamed arguments, and thus effectively skip the default ones.

This proposal is written purposefully to minimized its scope. Yes, the current proposal doesn't address this use case, but it doesn't prevent future DIPs from doing so.
February 15, 2019
On Friday, 15 February 2019 at 18:26:34 UTC, Yuxuan Shui wrote:
> Yes, one of my "design goal" is to maximize my chance :)

Increasing the chance of this DIP being accepted by avoiding code deprecation shouldn't be any DIP design goal. We shouldn't reject good design just because it may break people code.

That is THE ISSUE THAT I HAVE WITH THE C++ COMMITTEE! If I were so worried about breaking code when introducing new features I would use c++! Which guess what? The readability is horrible! So god awful! They are STILL stuck with using header files in spite of introducing modules! I can go on and on about this, but it be pointless, because they have such a religious devotion to backwards compatibility that I just gave up on them.

D should not make the fatal mistake of "persevering backwards capability at all cost" scenario, that what c++ is for.

Argue that the benefit of readability overweight the cost of breaking peoples code, which can be easily fix with the rename feature that comes with IDE and tools. Stand your ground. Please! I do not want to go around and beg package makers to label their functions @named for readability sake!

-Alex

February 15, 2019
On Friday, 15 February 2019 at 19:11:55 UTC, 12345swordy wrote:
> On Friday, 15 February 2019 at 18:26:34 UTC, Yuxuan Shui wrote:
>> Yes, one of my "design goal" is to maximize my chance :)
>
> Increasing the chance of this DIP being accepted by avoiding code deprecation shouldn't be any DIP design goal. We shouldn't reject good design just because it may break people code.
>
> [...]
>
> D should not make the fatal mistake of "persevering backwards capability at all cost" scenario, that what c++ is for.

It's actually worse than that--the purpose of @named is not to avoid breaking *existing* code. Existing code that doesn't use named arguments will continue to work regardless. The purpose of @named is to ensure that (a) changes to existing code which have yet to be made (b) do not break future code that has yet to be written.
February 15, 2019
On Friday, 15 February 2019 at 18:32:52 UTC, Yuxuan Shui wrote:
>> 5. Similarly, as already mentioned by somebody else, the DIP fails to explain interaction with function default arguments.
>
> I think it is reasonable to require a prefix of the parameters are specified.
>
> e.g. int fun(int a, int b = 1, int c = 2, int d = 3);
>
> The user can specify (a), (a, b), (a, b, c) or all of the parameters, and the arguments can be in any order.

In my experience, one of the greatest benefits of argument re-ordering is that it lets you leave out optional arguments at the call site. For example, in Python, if you wanted to use the default value for every argument except `d`, you could write this:

    fun(a=123, d=456)

...whereas with this proposal, you'd be required to needlessly repeat the default values for `a` and `b`:

    fun(a: 123, d: 456, b: 1, c: 2);

If this DIP isn't going to allow leaving out optional arguments in all cases, it might be better to simply forbid argument re-ordering entirely (or at least, to leave the issue for a future DIP).
February 15, 2019
On Friday, 15 February 2019 at 19:11:55 UTC, 12345swordy wrote:
> On Friday, 15 February 2019 at 18:26:34 UTC, Yuxuan Shui wrote:
>> Yes, one of my "design goal" is to maximize my chance :)
>
> Increasing the chance of this DIP being accepted by avoiding code deprecation shouldn't be any DIP design goal. We shouldn't reject good design just because it may break people code.
>
> That is THE ISSUE THAT I HAVE WITH THE C++ COMMITTEE! If I were so worried about breaking code when introducing new features I would use c++! Which guess what? The readability is horrible! So god awful! They are STILL stuck with using header files in spite of introducing modules! I can go on and on about this, but it be pointless, because they have such a religious devotion to backwards compatibility that I just gave up on them.
>
> D should not make the fatal mistake of "persevering backwards capability at all cost" scenario, that what c++ is for.
>
> Argue that the benefit of readability overweight the cost of breaking peoples code, which can be easily fix with the rename feature that comes with IDE and tools. Stand your ground. Please! I do not want to go around and beg package makers to label their functions @named for readability sake!
>
> -Alex

I am not saying "we should never break any code". I am deferring that decision to someone else. If someone want to make named parameters opt-out instead of opt-in, they can do so on top of this DIP. I am just not doing that in my proposal.
February 15, 2019
On Friday, 15 February 2019 at 20:11:47 UTC, Paul Backus wrote:
> On Friday, 15 February 2019 at 19:11:55 UTC, 12345swordy wrote:
>> On Friday, 15 February 2019 at 18:26:34 UTC, Yuxuan Shui wrote:
>>> Yes, one of my "design goal" is to maximize my chance :)
>>
>> Increasing the chance of this DIP being accepted by avoiding code deprecation shouldn't be any DIP design goal. We shouldn't reject good design just because it may break people code.
>>
>> [...]
>>
>> D should not make the fatal mistake of "persevering backwards capability at all cost" scenario, that what c++ is for.
>
> It's actually worse than that--the purpose of @named is not to avoid breaking *existing* code. Existing code that doesn't use named arguments will continue to work regardless. The purpose of @named is to ensure that (a) changes to existing code which have yet to be made (b) do not break future code that has yet to be written.
Which it is a non-issue in other languages such as C# as the simple find and replace tool in your favorite editor can simply fix the code breakage due to parameter name change.
This should really be opt-out rather then opt-in, as parameter name changes are rare and easy to fix. I don't think library authors should be nagged by user to put the @named attribute to their functions just so they can use Named Arguments! If the calle is so worried about their code break, because of the name change of the parameter, then they shouldn't be using name arguments at all!

I don't want Named Arguments to be dead on arrival, as your favorite library hasn't updated their functions to use the named arguments feature.

-Alex

February 15, 2019
On Friday, 15 February 2019 at 20:35:14 UTC, Yuxuan Shui wrote:
> On Friday, 15 February 2019 at 19:11:55 UTC, 12345swordy wrote:
>> [...]
>
> I am not saying "we should never break any code". I am deferring that decision to someone else. If someone want to make named parameters opt-out instead of opt-in, they can do so on top of this DIP. I am just not doing that in my proposal.

Why? We need to get it right the first time, as
a.)This is a slow process
b.)Would require another 180+ days if A&W reject this.