June 08, 2019
On Friday, 7 June 2019 at 13:27:12 UTC, Yuxuan Shui wrote:
> On Thursday, 6 June 2019 at 20:04:15 UTC, Walter Bright wrote:
>> I'll reiterate what I wrote for DIP1020 https://digitalmars.com/d/archives/digitalmars/D/DIP_1020--Named_Parameters--Community_Review_Round_1_325299.html#N325627
>>
>
> And how do you deal with:
>
>     void func(Args...)(Args args);
>
> ?

Something like func(args:(1,2,3));
`Name: TupleLiteral`
June 08, 2019
On Thursday, 6 June 2019 at 20:04:15 UTC, Walter Bright wrote:
> I'll reiterate what I wrote for DIP1020 https://digitalmars.com/d/archives/digitalmars/D/DIP_1020--Named_Parameters--Community_Review_Round_1_325299.html#N325627
>
> ---
>

> <snip>
> One nice thing about this is the { } struct initialization syntax can be
> deprecated, as S(a:1, b:2) can replace it, and would be interchangeable with
> constructor syntax, making for a nice unification. (Like was done for array
> initialization.)

This, plus what Timon added, seems to be a far superior alternative. I like it.
June 08, 2019
On Thursday, 6 June 2019 at 20:04:15 UTC, Walter Bright wrote:
> I'll reiterate what I wrote for DIP1020 https://digitalmars.com/d/archives/digitalmars/D/DIP_1020--Named_Parameters--Community_Review_Round_1_325299.html#N325627
>
> ---
>
> Here's a much simpler proposal, based on the recognition that D already has
> named parameters:
>
>    https://dlang.org/spec/struct.html#static_struct_init
>
> and related:
>
>    https://dlang.org/spec/hash-map.html#static_initialization
>    https://dlang.org/spec/arrays.html#static-init-static
>
> The only additional syntax would be allowing the equivalent of
> https://dlang.org/spec/hash-map.html#static_initialization in the argument
> list.
> Assignment of arguments to parameters would work the same way as assignments to
> fields.
>
> As for the semantics, given this constraint, nothing needs to be invented, just
> discovered as necessary behavior. Consider:
>
>     void snoopy(T t, int i, S s);     // A
>     void snoopy(S s, int i = 0; T t); // B
>
> and calling it:
>
>     S s; T t; int i;
>     snoopy(t, i, s); // A
>     snoopy(s, i, t); // B
>     snoopy(s, t); // error, neither A nor B match
>     snoopy(t, s); // error, neither A nor B match
>     snoopy(s:s, t:t, i:i); // error, ambiguous
>     snoopy(s:s, t:t); // B
>     snoopy(t:t, s:s); // B

Unlike the other cases, this one seems particularly surprising.

>     snoopy(t:t, i, s:s); // A
>     snoopy(s:s, t:t, i); // A

This is another re-ordering case, which makes my brain have to strain for a second.

>
> I.e. function resolution is done by constructing an argument list separately
> for
> each function before testing it for matching. Of course, if the parameter
> name(s) don't match, the function doesn't match. If a parameter has no
> corresponding argument, and no default value, then the function doesn't match.
>
> I don't see much point in requiring the names, preventing use of names, nor
> aliasing them. This has never been an issue for struct initializers.
>
> One nice thing about this is the { } struct initialization syntax can be
> deprecated, as S(a:1, b:2) can replace it, and would be interchangeable with
> constructor syntax, making for a nice unification. (Like was done for array
> initialization.)
>
> One issue would be order of evaluation: would the arguments be evaluated in the
> lexical order of the arguments, or the lexical order of the parameters?
>
> Rationale:
>
> Although this supports reordering, the real reason for naming is so one can
> have
> a function with a longish list of parameters, each with a reasonable default,
> and the user need only supply the arguments that matter for his use case. This
> is much more flexible than the current method of putting all the defaults at
> the
> end of the parameter list, and defaulting one means all the rest get defaulted.
>
> A secondary reason is (again) for a longish list of parameters, when the user
> finds himself counting parameters to ensure they line up, then named parameters
> can be most helpful.

I see value in allowing a caller to omit arguments that have default values, but what is the value in allowing the caller to reorder them?

Allowing re-ordering seems to cause surprising results, such as the ones I noted above, and also causes a new decision to made, namely, which order should arguments be evaluated in (which you noted).  It also means that in order to understand what overload you are calling, you need to check EVERY argument before you can determine this.  If you don't allow re-ordering, you can rule out overloads sooner as you only need to check whether the next named argument matches the next named parameter.  To demonstrate, in the above example, if I saw

>     snoopy(t:t,...

I can immediately rule out overload B since parameter `s` must always come before `t`.  I don't have to check the rest of the arguments to see if there is a "s: ...", and then make sure to remember that it does as I move through the rest of the parameters.  The amount of memory a human will need to track while evaluating which overload is taken as the number of parameters grows will be unmanageable if re-ordering is allowed.  And, usually the most useful cases for this are the ones where there are alot of parameters.


June 08, 2019
On Saturday, 8 June 2019 at 18:05:43 UTC, Jonathan Marler wrote:
> On Thursday, 6 June 2019 at 20:04:15 UTC, Walter Bright wrote:
>>     [...]
>
> Unlike the other cases, this one seems particularly surprising.
>
>>     [...]
>
> This is another re-ordering case, which makes my brain have to strain for a second.
>
>> [...]
>
> I see value in allowing a caller to omit arguments that have default values, but what is the value in allowing the caller to reorder them?
>
> Allowing re-ordering seems to cause surprising results, such as the ones I noted above, and also causes a new decision to made, namely, which order should arguments be evaluated in (which you noted).  It also means that in order to understand what overload you are calling, you need to check EVERY argument before you can determine this.  If you don't allow re-ordering, you can rule out overloads sooner as you only need to check whether the next named argument matches the next named parameter.  To demonstrate, in the above example, if I saw
>
>>     [...]
>
> I can immediately rule out overload B since parameter `s` must always come before `t`.  I don't have to check the rest of the arguments to see if there is a "s: ...", and then make sure to remember that it does as I move through the rest of the parameters.  The amount of memory a human will need to track while evaluating which overload is taken as the number of parameters grows will be unmanageable if re-ordering is allowed.  And, usually the most useful cases for this are the ones where there are alot of parameters.

By the way, I think your proposal is basically DIP 1019 except allowing default arguments to be skipped and allowing re-ordering.

But again, I maintain that re-ordering seems to be add more confusion than it does value.

Reordering isn't a problem with struct initialization as there's no such thing as struct initialization overloading :)
June 08, 2019
On Saturday, 8 June 2019 at 06:44:56 UTC, Andrei Alexandrescu wrote:
> On 6/5/19 9:03 AM, Mike Parker wrote:
>> This is the feedback thread for the second round of Community Review for DIP 1019, "Named Arguments Lite":
>> 
>> https://github.com/dlang/DIPs/blob/9c9cc39246de4c449fe1e6cb6b27f7e426ff1eb9/DIPs/DIP1019.md
>
> Things that I think would make this DIP stronger:
>
> * The presence of the feature in other programming languages belongs in "rationale" if also the rationale pertaining to those other languages is present. Otherwise it's argument by majority. Normally "rationale" would stand on its own (possibly using examples drawn/inspired from other languages) and mention of other languages would go in the "related work" section (which presently is missing).

Given that there are a fair number of programming languages that have implemented named parameters, it might make sense to go a bit further and provide a summary of the different goals and approaches that have been used elsewhere. That would make it easier to compare the proposal to related efforts. There may well be published papers that provide such comparisons. A starting point list of languages with named parameters can be found here: https://en.wikipedia.org/wiki/Named_parameter

--Jon

June 08, 2019
On Saturday, 8 June 2019 at 06:44:56 UTC, Andrei Alexandrescu wrote:
> On 6/5/19 9:03 AM, Mike Parker wrote:
>> This is the feedback thread for the second round of Community Review for DIP 1019, "Named Arguments Lite":
>> 
>> https://github.com/dlang/DIPs/blob/9c9cc39246de4c449fe1e6cb6b27f7e426ff1eb9/DIPs/DIP1019.md
>
> [initially posted in the wrong thread, pasting here for conformity]

Thanks for the feedback!

I will try to address some of your points.

>
>
> Things that I think would make this DIP stronger:
>
> * The presence of the feature in other programming languages belongs in "rationale" if also the rationale pertaining to those other languages is present. Otherwise it's argument by majority. Normally "rationale" would stand on its own (possibly using examples drawn/inspired from other languages) and mention of other languages would go in the "related work" section (which presently is missing).
>
> (@Michael we need to make "Related Work" a required section.)

Will do.

>
> * The example with "CalculateProduct(values, 7, false, null);" in the rationale should be completed with the best-of-the-breed solution in the current D language, i.e. using Flag. Currently Flag is not being discussed at all and it should because it is a workaround to named parameters (however insufficient as the proposal might argue).

Will do.

>
> * The argument with repurposing argument is weak because code that doesn't use named parameters would be broken anyway, which makes the idea of repurposing parameters bad to start with. I suggest it be dropped, or mentioned later as a perk of named parameters.

The point is named parameters prevents silent breakage. Which I think is a significant benefit.

Of course, code that do not use named parameters won't get the benefit of named parameters. This is just the natural of things and shouldn't be used as a point against the point.

>
> * "The relevance of forward declarations will become clear later." -> "Section xyz clarifies the relevance of forward declarations."
>
> * "Named arguments proposed by this DIP have no effect on the ordering of arguments in function calls." Related work will in all likelihood reveal that reordering arguments in large argument lists is a key advantage of named arguments. Not availing ourselves of that advantage is a serious issue that weakens the proposal. It must explain why it is not possible to allow reordering of arguments (or better yet work out the mechanics to allow it).

Reordering is definitely a very important feature. However, this proposal is not going to be the last DIP about named parameters, as is stressed in the proposal itself.

Generally, I think incremental improvements should be allowed.

>
> * "Named arguments proposed by this DIP do not allow default parameters to be skipped." Not sure what "skipped" means in context; I assume it means some defaulted arguments would be left unspecified and other following them would be specified with non-default values. My understanding is that this is another key advantage of named arguments in related work - typically complex functions with large argument lists like CreateWindow, CreateArchive etc. would have many arguments defaulted to reasonable values, which then the caller can pick and choose which to customize. I assume a large part of what makes Python APIs so friendly is this ability. The DIP should explain why this is not desirable or achievable for the D language (or again better yet make it just work).

Same as the above one.

>
> * "Variadic arguments can be labeled with the name of the variadic parameter and a subscript." seems to have little value if there's only one variadic per function and all indexes must be specified in order. The DIP should explain why this feature (the index can be any compile-time expression... right?) is useful.

index can only be integer literals, as is specified in the "Grammar changes" section.

This exists to avoid confusion that might arise from labeling multiple arguments with the same name.

>
> * "If a function is defined with some of its parameter names omitted, arguments to those parameters can labeled with an empty name." The utility of this should be explained.

This feature is here for completeness and consistency, so there is not a case where an argument cannot be labeled.

Unless there is a strong disadvantage of allowing this, I think this should stay.

>
> * "This seems to be the biggest concern among people who are against named arguments." This is vague and nonscientific and has no place in a DIP. Who are those (does it even matter), where are the relevant exchanges, how did the author arrive at the conclusion that this is the biggest concern. The concern should be discussed at face value and if appropriate rebutted soundly with an analysis of the tradeoff (I assume it's not "all bad" vs "all good" but more like pros and cons).

Good point.

>
> * "Allow calling the same function with a different set of parameter names." The advantage of this seems to be backward compatibility, but it endorses a technique that is questionable in the first place.

Can you elaborate why is this questionable?

>
> * "This DIP does not prohibit future proposals for adding parameter reordering, partially-specified parameter names with reordering, named template parameters, omission of default arguments by using named arguments, and other similar things." The problem here is that all of these (easily anticipated as desirable) weaken the DIP by their absence from it.

The point I want to make it that you shouldn't compare this DIP to some idealized, optimal DIP you imagined. You should evaluate it by comparing it to what we have now. Especially for a DIP that allows (anticipates, even) further improvements.

If this DIP is a net improvement, and no major concern exists against it, I don't see why it cannot be accepted just because it doesn't give us all the things we want at once.
June 09, 2019
On Saturday, 8 June 2019 at 18:05:43 UTC, Jonathan Marler wrote:
> I see value in allowing a caller to omit arguments that have default values, but what is the value in allowing the caller to reorder them?

Without looking at the documentation, which of the following calls would fail to compile if argument reordering was forbidden?

spawnProcess("/usr/bin/sort", stdout: outputFile, stdin: inputFile);
spawnProcess("/usr/bin/sort", stdin: inputFile, stdout: outputFile);

From a usability perspective, it's completely insane for only one of these to work.
June 09, 2019
On Sunday, 9 June 2019 at 01:34:50 UTC, Paul Backus wrote:
> On Saturday, 8 June 2019 at 18:05:43 UTC, Jonathan Marler wrote:
>> I see value in allowing a caller to omit arguments that have default values, but what is the value in allowing the caller to reorder them?
>
> Without looking at the documentation, which of the following calls would fail to compile if argument reordering was forbidden?
>
> spawnProcess("/usr/bin/sort", stdout: outputFile, stdin: inputFile);
> spawnProcess("/usr/bin/sort", stdin: inputFile, stdout: outputFile);
>
> From a usability perspective, it's completely insane for only one of these to work.

Of the top of my head stdin is first...but I don't think many people would know that.  It's just that I've written wrappers to spawnProcess so many times that it's ingrained in my head.  But I think whether or not I know is irrelevent to your point :)

I believe that optimizing code for the reader should take priority over optimizing for the writer.  The antithetical example is the perl language...writing it can be terse and quick but reading it can make your head spin.

I think your point is that when developers write code like this, having to put arguments in a particular order seems like an unnecessary burden.  I agree it's an extra burden on the writer, but enforcing the same order reduces the complexity of overload resolution and knowing how to map arguments to parameters, something which the "reader" needs to be able to do whenever they see a function call.

Consider,

foo(int a, int b, int c, int d, int e, int f);

foo(1, 2, 3, 4, 5, 6); // a=1, b=2, c=3, d=4, e=5, f=6

Now let's see it with some argument re-ordering:

foo(6, c=1, e=2, 3, b=4, e=5, a=7);

What's the values of a/b/c/d/e/f in this case? This may have made sense when it was written, but this is not beneficial for the reader.

This gets worse when you introduce the concept of order-of-evaluation:

int x = 0;
foo(x++, c=x++, e=x++, x++, b=x++, e=x++, a=x++);

Now what are the values of a/b/c/d/e/f?  Do you evaluate arguments in the order of the call, or the order of the function definition?

These are the problems before you get into overloading.  Now add that into the mix:

foo(float a, float b, float c, int   d, float e, float f);
foo(float a, float b, float c, float d, float e, int f);

foo(0, c=1, 2.0, 0.0, b=4, e=5, a=7);

...

Keep in mind that I'm not saying that by enabling re-ordering we're going to start having a huge mass of unreadable code like this.  These examples are contrived to show you how re-ordering can make things confusing.  But when you enable powerful things like this, you are adding an extra burden on the reader every time they see a function call.  The more rules you add, the more unsure you make the reader and the more rules the reader has to remember and evaluate in order to understand the code.  Now whenever they see a function call with named arguments, they're going to have to go through a mental checklist of rules to be sure which overload is actually being called and which parameters are receiving which arguments.

The benefit of allowing the writer to re-order arguments should be weighed against the burden of the reader to then understand it later when they do.

June 09, 2019
On 6/8/19 2:05 PM, Jonathan Marler wrote:
> I see value in allowing a caller to omit arguments that have default values, but what is the value in allowing the caller to reorder them?

Named arguments is useful mainly so one doesn't need to remember their order in large argument lists.
June 09, 2019
On 6/8/19 3:02 PM, Jon Degenhardt wrote:
> On Saturday, 8 June 2019 at 06:44:56 UTC, Andrei Alexandrescu wrote:
>> On 6/5/19 9:03 AM, Mike Parker wrote:
>>> This is the feedback thread for the second round of Community Review for DIP 1019, "Named Arguments Lite":
>>>
>>> https://github.com/dlang/DIPs/blob/9c9cc39246de4c449fe1e6cb6b27f7e426ff1eb9/DIPs/DIP1019.md 
>>>
>>
>> Things that I think would make this DIP stronger:
>>
>> * The presence of the feature in other programming languages belongs in "rationale" if also the rationale pertaining to those other languages is present. Otherwise it's argument by majority. Normally "rationale" would stand on its own (possibly using examples drawn/inspired from other languages) and mention of other languages would go in the "related work" section (which presently is missing).
> 
> Given that there are a fair number of programming languages that have implemented named parameters, it might make sense to go a bit further and provide a summary of the different goals and approaches that have been used elsewhere. That would make it easier to compare the proposal to related efforts. There may well be published papers that provide such comparisons. A starting point list of languages with named parameters can be found here: https://en.wikipedia.org/wiki/Named_parameter
> 
> --Jon

Yes please!