www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Discussion Thread: DIP 1030--Named Arguments--Final Review

reply Mike Parker <aldacron gmail.com> writes:
This is the discussion thread for the Final Review of DIP 1030, 
"Named Arguments":

https://github.com/dlang/DIPs/blob/7d114c93edb02d8fc4b05f0716bdb6057905fec2/DIPs/DIP1030.md

The review period will end at 11:59 PM ET on May 25, or when I 
make a post declaring it complete. Discussion in this thread may 
continue beyond that point.

Here in the discussion thread, you are free to discuss anything 
and everything related to the DIP. Express your support or 
opposition, debate alternatives, argue the merits, etc.

However, if you have any specific feedback on how to improve the 
proposal itself, then please post it in the feedback thread. The 
feedback thread will be the source for the review summary I write 
at the end of this review round. I will post a link to that 
thread immediately following this post. Just be sure to read and 
understand the Reviewer Guidelines before posting there:

https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md

And my blog post on the difference between the Discussion and 
Feedback threads:

https://dlang.org/blog/2020/01/26/dip-reviews-discussion-vs-feedback/

Please stay on topic here. I will delete posts that are 
completely off-topic.
May 11
next sibling parent Mike Parker <aldacron gmail.com> writes:
On Monday, 11 May 2020 at 11:37:07 UTC, Mike Parker wrote:

 However, if you have any specific feedback on how to improve 
 the proposal itself, then please post it in the feedback 
 thread. The feedback thread will be the source for the review 
 summary I write at the end of this review round. I will post a 
 link to that thread immediately following this post.
The Feedback Thread is here: https://forum.dlang.org/post/lzpzaoaxzcxeijegfhkz forum.dlang.org
May 11
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
The biggest problem I had with this DIP still remains -- You cannot 
forward the "namedness" of parameters to a subtype.

Consider the following, which is supposed to wrap a subtype:

struct S
{
     int foo(int bar) {...}
}

struct LogCalls!T
{
    private T _wrapped;
    auto ref opDispatch(string f, Args...)(auto ref Args args)
    {
        log("Calling ", f);
        mixin("return " ~ f ~ "(args);");
    }
}

This works today and can be used to reasonably wrap everything that T 
can do.

But with this named parameters DIP, then we have problems:

// S s;
LogCalls!S s; // I want to log things temporarily

s.foo(bar: 5); // error

I think this is important to solve. Because you have types whose "API" 
is "I will wrap everything this type does", and this breaks the promise 
with no possibility of a fix. While everything that compiles today will 
compile tomorrow, code will migrate to using named args, and then you 
can't use these wrappers, or you have to explicitly forbid users from 
using named arguments.

Discussed here: 
https://forum.dlang.org/post/mailman.1114.1581363532.31109.digitalmars-d puremagic.com

And this was my reply at that time:
https://forum.dlang.org/post/r1uaph$2pkl$1 digitalmars.com

A possible solution is to accept a string[] arg as the first parameter 
in opDispatch, so the names can be captured. This also allows an opt-in 
so current opDispatch cannot be called via named parameters.

Another possible mechanism is to provide a __traits call to get argument 
names, but the issue here is that then you can call code that isn't 
written to handle named args with named args and the right thing might 
not happen.

Another possibility is to provide a second variadic parameter e.g.:

opDispatch(string f, Args..., string[] names...)(Args args)

Where names will be filled in with the names provided by the caller, or 
null if not provided.

This is also a nice opt-in, as it doesn't compile today.

-Steve
May 11
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 5/11/2020 5:48 AM, Steven Schveighoffer wrote:
 The biggest problem I had with this DIP still remains -- You cannot forward
the 
 "namedness" of parameters to a subtype.
I see this as something you can propose as another DIP to enhance DIP1030 after it is incorporated.
May 11
parent reply Gregory <g.thompson.1892 gmall.com> writes:
On Tuesday, 12 May 2020 at 05:36:11 UTC, Walter Bright wrote:
 On 5/11/2020 5:48 AM, Steven Schveighoffer wrote:
 The biggest problem I had with this DIP still remains -- You 
 cannot forward the "namedness" of parameters to a subtype.
I see this as something you can propose as another DIP to enhance DIP1030 after it is incorporated.
It's a feature that would be lost, I don't think named arguments should be included without this feature. Without ironing out the details now, who's to say that a suitable solution exists to the problem? There's no obvious solution to a problem that should be solved. I also don't like that you can rearrange the arguments into a different order. Especially that you can put default arguments in the middle. By doing so you are forcing users to use named allows defaults at the end, and named arguments still need to be in the correct order. I don't see *any* benefit, nor does the DIP describe what benefit this provides. On the other hand this makes it more difficult to read, especially (as with the example) both functions have the same exact names for their parameters. THIS is a feature that should be removed, and if it is deemed necessary at a later date then it can be incorporated with another DIP. Otherwise trying to fix this later on when it is already in use will be almost impossible without breaking any code that uses it.
May 12
next sibling parent reply Paulo Pinto <pjmlp progtools.org> writes:
On Tuesday, 12 May 2020 at 12:11:11 UTC, Gregory wrote:
 On Tuesday, 12 May 2020 at 05:36:11 UTC, Walter Bright wrote:
 On 5/11/2020 5:48 AM, Steven Schveighoffer wrote:
 The biggest problem I had with this DIP still remains -- You 
 cannot forward the "namedness" of parameters to a subtype.
I see this as something you can propose as another DIP to enhance DIP1030 after it is incorporated.
It's a feature that would be lost, I don't think named arguments should be included without this feature. Without ironing out the details now, who's to say that a suitable solution exists to the problem? There's no obvious solution to a problem that should be solved. I also don't like that you can rearrange the arguments into a different order. Especially that you can put default arguments in the middle. By doing so you are forcing users to use named allows defaults at the end, and named arguments still need to be in the correct order. I don't see *any* benefit, nor does the DIP describe what benefit this provides. On the other hand this makes it more difficult to read, especially (as with the example) both functions have the same exact names for their parameters. THIS is a feature that should be removed, and if it is deemed necessary at a later date then it can be incorporated with another DIP. Otherwise trying to fix this later on when it is already in use will be almost impossible without breaking any code that uses it.
more flexible.
May 12
parent reply Gregory <g.thompson.1892 gmall.com> writes:
On Tuesday, 12 May 2020 at 12:40:47 UTC, Paulo Pinto wrote:
 On Tuesday, 12 May 2020 at 12:11:11 UTC, Gregory wrote:
 On Tuesday, 12 May 2020 at 05:36:11 UTC, Walter Bright wrote:
 On 5/11/2020 5:48 AM, Steven Schveighoffer wrote:
 The biggest problem I had with this DIP still remains -- You 
 cannot forward the "namedness" of parameters to a subtype.
I see this as something you can propose as another DIP to enhance DIP1030 after it is incorporated.
It's a feature that would be lost, I don't think named arguments should be included without this feature. Without ironing out the details now, who's to say that a suitable solution exists to the problem? There's no obvious solution to a problem that should be solved. I also don't like that you can rearrange the arguments into a different order. Especially that you can put default arguments in the middle. By doing so you are forcing users to use named only allows defaults at the end, and named arguments still need to be in the correct order. I don't see *any* benefit, nor does the DIP describe what benefit this provides. On the other hand this makes it more difficult to read, especially (as with the example) both functions have the same exact names for their parameters. THIS is a feature that should be removed, and if it is deemed necessary at a later date then it can be incorporated with another DIP. Otherwise trying to fix this later on when it is already in use will be almost impossible without breaking any code that uses it.
more flexible.
that relaxes them further. But it didn't change the requirement for defaults or positioning.
May 12
parent Paulo Pinto <pjmlp progtools.org> writes:
On Tuesday, 12 May 2020 at 13:08:52 UTC, Gregory wrote:
 On Tuesday, 12 May 2020 at 12:40:47 UTC, Paulo Pinto wrote:
 On Tuesday, 12 May 2020 at 12:11:11 UTC, Gregory wrote:
 [...]
made more flexible.
8 that relaxes them further. But it didn't change the requirement for defaults or positioning.
You're right I was mixing that with now being able to change the order of named arguments.
May 12
prev sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 12 May 2020 at 12:11:11 UTC, Gregory wrote:
 I also don't like that you can rearrange the arguments into a 
 different order. Especially that you can put default arguments 
 in the middle. By doing so you are forcing users to use named 

 allows defaults at the end, and named arguments still need to 
 be in the correct order. I don't see *any* benefit, nor does 
 the DIP describe what benefit this provides. On the other hand 
 this makes it more difficult to read, especially (as with the 
 example) both functions have the same exact names for their 
 parameters. THIS is a feature that should be removed, and if it 
 is deemed necessary at a later date then it can be incorporated 
 with another DIP. Otherwise trying to fix this later on when it 
 is already in use will be almost impossible without breaking 
 any code that uses it.
The logic behind this feature is that the rules it uses for re-ordering are the same ones already used for struct initializers [1], which are in turn based on the rules used for designated initializers in C99 [2]. These rules aren't perfect, but consistently using the same rules for everything is much better than having two separate sets of rules, and it's too late to go back and change the struct-initialization syntax now. [1] https://dlang.org/spec/struct.html#static_struct_init
May 12
parent Walter Bright <newshound2 digitalmars.com> writes:
On 5/12/2020 10:42 AM, Paul Backus wrote:
 The logic behind this feature is that the rules it uses for re-ordering are
the 
 same ones already used for struct initializers [1], which are in turn based on 
 the rules used for designated initializers in C99 [2].
 
 These rules aren't perfect, but consistently using the same rules for
everything 
 is much better than having two separate sets of rules, and it's too late to go 
 back and change the struct-initialization syntax now.
 
 [1] https://dlang.org/spec/struct.html#static_struct_init

Thank you for the clear explanation. Consider the convention that turning a valve clockwise shuts it, and counterclockwise opens it. This matches the convention for tightening and loosening a bolt. It matches a meter where more is clockwise. Except for the hot water faucet, which goes the other way. I always have to stop and think when I use the hot water faucet. Consistency and predictability are huge advantages in user interfaces, and override small optimizations.
May 12
prev sibling next sibling parent reply Jonathan Marler <johnnymarler gmail.com> writes:
On Monday, 11 May 2020 at 11:37:07 UTC, Mike Parker wrote:
 This is the discussion thread for the Final Review of DIP 1030, 
 "Named Arguments":

 https://github.com/dlang/DIPs/blob/7d114c93edb02d8fc4b05f0716bdb6057905fec2/DIPs/DIP1030.md

 The review period will end at 11:59 PM ET on May 25, or when I 
 make a post declaring it complete. Discussion in this thread 
 may continue beyond that point.

 Here in the discussion thread, you are free to discuss anything 
 and everything related to the DIP. Express your support or 
 opposition, debate alternatives, argue the merits, etc.

 However, if you have any specific feedback on how to improve 
 the proposal itself, then please post it in the feedback 
 thread. The feedback thread will be the source for the review 
 summary I write at the end of this review round. I will post a 
 link to that thread immediately following this post. Just be 
 sure to read and understand the Reviewer Guidelines before 
 posting there:

 https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md

 And my blog post on the difference between the Discussion and 
 Feedback threads:

 https://dlang.org/blog/2020/01/26/dip-reviews-discussion-vs-feedback/

 Please stay on topic here. I will delete posts that are 
 completely off-topic.
I'd really like to see the DIP include a proposal on parameter naming conventions for the standard libraries before we enable this. For example, Walter mentioned in the discussion thread that when creating function wrappers for external APIs, we should use the same name from the original function. (see https://forum.dlang.org/post/r1us6g$11gs$1 digitalmars.com). However I don't see this convention mentioned anywhere in the DIP and I don't think the choice to do it this way is "self-evident". Coming up with conventions after we enable this could cause quite a bit of headache and debate about when to create wrappers to support old parameter name overloads and how much time before we remove the deprecations. There will be much less "friction" to fix these names if we do so before enabling the feature. Here's a start for how these conventions could look: Parameter Naming Conventions --------------------------------------------------------------------- First, the parameter names of a function should only be modified if exposing the names helps the caller in some way. For example, you needn't bother with the name of the parameter in a function such as "floor": floor(x); floor(x:x); // not helpful A sleep function that takes milliseconds on the other hand could be helpful: sleep(100); sleep(msecs:100); // helpful Given that, here are a list of conventions: 1. When wrapping another API, use the names from the original. For example, all Windows functions should use the names from the original Windows headers and documentation. 2. Common generic parameter names p (generic pointer argument, prefer this over ptr or pointer) s (generic string argument, prefer this over str or string) i (generic integer argument) msecs secs 3. ... I feel that including a set of conventions in the DIP will be worth the effort now, and save us from alot of effort later, even if it ends up delaying this feature to a degree.
May 11
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2020-05-12 08:22, Jonathan Marler wrote:

 Coming up with conventions after we enable this could cause quite a bit 
 of headache and debate about when to create wrappers to support old 
 parameter name overloads and how much time before we remove the 
 deprecations.  There will be much less "friction" to fix these names if 
 we do so before enabling the feature.
I agree.
 Here's a start for how these conventions could look:
 
 Parameter Naming Conventions
 ---------------------------------------------------------------------
 First, the parameter names of a function should only be modified if 
 exposing the names helps the caller in some way.  For example, you 
 needn't bother with the name of the parameter in a function such as 
 "floor":
 
 floor(x);
 floor(x:x); // not helpful
Yes, I agree.
 A sleep function that takes milliseconds on the other hand could be 
 helpful:
 
 sleep(100);
 sleep(msecs:100); // helpful
I disagree. It's much better what we already have. The `sleep` method on `Thread` takes a duration, instead of a specific time unit. The duration is also encoded in its own type: Thread.getThis.sleep(100.msecs); Thread.getThis.sleep(1.seconds); // this works too I guess one could do this: Thread.getThis.sleep(duration: 1.seconds); Not sure if it would help though. Instead of passing a random integer, we pass a type that encodes the meaning of the value. It's also more flexible, because you can create a Duration out of many different units.
 Given that, here are a list of conventions:

 2. Common generic parameter names
 
 p (generic pointer argument, prefer this over ptr or pointer)
 s (generic string argument, prefer this over str or string)
 i (generic integer argument)
I disagree. I think there are very few cases of APIs where a function expects a truly generic value. It's better to try to encode the purpose or how a value is used in the parameter name. Naming something based on what it is rarely useful, we have a much better system for that, which is the type system :). For example: void foo(int* p); void foo(int* pointer); void foo(int* ptr); The signature already contains the information that the parameter is a pointer, no need to encode that in the name, be it `pointer`, `ptr` or `p`. There are cases where a function accepts a truly generic value, like a function that can convert any value to a string: string toString(T)(T value); toString(value: 3); But in this case named arguments don't help much and I think it falls under the first category (your example with `floor`). Better to call it like: toString(3); 3.toString();
 msecs
 secs
Same thing as the `sleep` method. Should not be a plain int, should be its own type. Also, we should avoiding having short, abbreviated symbol names (any kind of symbol names, not just parameter names). Although it's worse to have abbreviated names which are part of the API or show up in generated documentation. There are always exceptions, like when abbreviated name is more known and common than the actual full name. Examples are: HTTP, FTP and so on. -- /Jacob Carlborg
May 13
next sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On Wednesday, 13 May 2020 at 08:17:26 UTC, Jacob Carlborg wrote:
 On 2020-05-12 08:22, Jonathan Marler wrote:
 [...]
I disagree. It's much better what we already have. The `sleep` method on `Thread` takes a duration, instead of a specific time unit. The duration is also encoded in its own type:
[snip] Exactly my thoughts, well put Jacob!
 [...]
I disagree. I think there are very few cases of APIs where a function expects a truly generic value. It's better to try to encode the purpose or how a value is used in the parameter name. [snip]
Again, pure gold and spot on. — Dmitry Olshansky Stay safe and have fun!
May 13
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/13/20 4:17 AM, Jacob Carlborg wrote:
 On 2020-05-12 08:22, Jonathan Marler wrote:
 A sleep function that takes milliseconds on the other hand could be 
 helpful:

 sleep(100);
 sleep(msecs:100); // helpful
I disagree. It's much better what we already have. The `sleep` method on `Thread` takes a duration, instead of a specific time unit. The duration is also encoded in its own type: Thread.getThis.sleep(100.msecs); Thread.getThis.sleep(1.seconds); // this works too
I love the Duration factory functions, one of the best parts of D. Just wanted to point out here that sleep is a static function, so you only need to do Thread.sleep(1.seconds). I also wanted to say that the example has to do with existing code, not specifically the way to sleep in D. The example is *if you have* a sleep function that takes milliseconds, as could be in a library other than druntime (like say an event library that needs to listen for other events for other fibers). While it might be nice to adjust such a function to take a Duration, that would be a breaking change, and simply changing the name to reflect better the parameter would be a non-breaking first step.
 Given that, here are a list of conventions:

 2. Common generic parameter names

 p (generic pointer argument, prefer this over ptr or pointer)
 s (generic string argument, prefer this over str or string)
 i (generic integer argument)
I disagree. I think there are very few cases of APIs where a function expects a truly generic value. It's better to try to encode the purpose or how a value is used in the parameter name. Naming something based on what it is rarely useful, we have a much better system for that, which is the type system :). For example: void foo(int* p); void foo(int* pointer); void foo(int* ptr); The signature already contains the information that the parameter is a pointer, no need to encode that in the name, be it `pointer`, `ptr` or `p`.
I agree, but also there's a lack of convincing examples here. I would say for pointers or references where data is to be read, `src` is a good name, and `dest` is a good name for a pointer to data to be written. e.g.: copyTo(T)(ref T src, ref T dest); Other than that, I can't really imagine that there's any hard rule that we need to adhere to -- pointers are passed for various reasons, you should identify the purpose with the name.
 There are cases where a function accepts a truly generic value, 
 like a function that can convert any value to a string:
 
 string toString(T)(T value);
 toString(value: 3);
 
 But in this case named arguments don't help much and I think it falls 
 under the first category (your example with `floor`). Better to call it 
 like:
 
 toString(3);
 3.toString();
Agree.
 Also, we should avoiding having short, abbreviated symbol names (any 
 kind of symbol names, not just parameter names). Although it's worse to 
 have abbreviated names which are part of the API or show up in generated 
 documentation. There are always exceptions, like when abbreviated name 
 is more known and common than the actual full name. Examples are: HTTP, 
 FTP and so on.
HTTP and FTP are acronyms, which in my opinion ARE the full names. Abbreviations are fine when the abbreviation is unambiguous, like src and dest. One thing that should be added: for overloaded functions, names of similar parameters should be the same. Though I suppose one could select a specific overload for literals using naming? Is that something that should be promoted? e.g.: double atan(double doubleVal); real atan(real realVal); -Steve
May 13
parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 13 May 2020 at 12:15:38 UTC, Steven Schveighoffer 
wrote:
 On 5/13/20 4:17 AM, Jacob Carlborg wrote:
 On 2020-05-12 08:22, Jonathan Marler wrote:
 Also, we should avoiding having short, abbreviated symbol 
 names (any kind of symbol names, not just parameter names). 
 Although it's worse to have abbreviated names which are part 
 of the API or show up in generated documentation. There are 
 always exceptions, like when abbreviated name is more known 
 and common than the actual full name. Examples are: HTTP, FTP 
 and so on.
HTTP and FTP are acronyms, which in my opinion ARE the full names. Abbreviations are fine when the abbreviation is unambiguous, like src and dest.
Even with such unambiguous abbreviations, the programmer still has to keep track of (a) which words are abbreviated and which are spelled out ("is it `source` or `src`?"), and (b) which abbreviations are used for words with multiple possibilities (e.g., "is it `dest` or `dst`?"). Spelling everything out means you never have to think about this stuff at all--there's always exactly one obvious, correct choice.
May 13
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/13/20 9:34 AM, Paul Backus wrote:
 On Wednesday, 13 May 2020 at 12:15:38 UTC, Steven Schveighoffer wrote:
 On 5/13/20 4:17 AM, Jacob Carlborg wrote:
 On 2020-05-12 08:22, Jonathan Marler wrote:
 Also, we should avoiding having short, abbreviated symbol names (any 
 kind of symbol names, not just parameter names). Although it's worse 
 to have abbreviated names which are part of the API or show up in 
 generated documentation. There are always exceptions, like when 
 abbreviated name is more known and common than the actual full name. 
 Examples are: HTTP, FTP and so on.
HTTP and FTP are acronyms, which in my opinion ARE the full names. Abbreviations are fine when the abbreviation is unambiguous, like src and dest.
Even with such unambiguous abbreviations, the programmer still has to keep track of (a) which words are abbreviated and which are spelled out ("is it `source` or `src`?"), and (b) which abbreviations are used for words with multiple possibilities (e.g., "is it `dest` or `dst`?"). Spelling everything out means you never have to think about this stuff at all--there's always exactly one obvious, correct choice.
If it's always abbreviated (in a certain project, for instance), then it's obvious, even as an abbreviation. What you shouldn't have is a project with functions that have `dest` and `dst`. You are not going to ever get global consensus for every project on every name. What I was saying is, intra-project consistency is more important than forbidding abbreviations. Even when abbreviations are not allowed, you can have different spellings (is it `color` or `colour`?) Naming conventions for parameters really should just look to naming conventions for functions for guidance I think. Many of the same rules apply. -Steve
May 13
prev sibling parent Jonathan Marler <johnnymarler gmail.com> writes:
On Wednesday, 13 May 2020 at 08:17:26 UTC, Jacob Carlborg wrote:
 On 2020-05-12 08:22, Jonathan Marler wrote:
 A sleep function that takes milliseconds on the other hand 
 could be helpful:
 
 sleep(100);
 sleep(msecs:100); // helpful
I disagree. It's much better what we already have. The `sleep` method on `Thread` takes a duration, instead of a specific time unit. The duration is also encoded in its own type:
Yes I also agree that what we have in phobos is already better than this. I was just showing an example of a theoretical sleep function that already took a integer value of milliseconds. This was a poor example on my part.
 Given that, here are a list of conventions:

 2. Common generic parameter names
 
 p (generic pointer argument, prefer this over ptr or pointer)
 s (generic string argument, prefer this over str or string)
 i (generic integer argument)
I disagree. I think there are very few cases of APIs where a function expects a truly generic value. It's better to try to encode the purpose or how a value is used in the parameter name. Naming something based on what it is rarely useful, we have a much better system for that, which is the type system :). For example:
Good point, if we defer to the first rule, there may be no need to have a convention for generic parameters like these.
 msecs
 secs
Same thing as the `sleep` method. Should not be a plain int, should be its own type.
When we can yes. However the C sleep function does take an integer, in which case we can use the parameter name for clarification. https://linux.die.net/man/3/sleep extern "C" uint sleep(uint seconds); sleep(2); sleep(seconds:2);
 Also, we should avoiding having short, abbreviated symbol names 
 (any kind of symbol names, not just parameter names). Although 
 it's worse to have abbreviated names which are part of the API 
 or show up in generated documentation. There are always 
 exceptions, like when abbreviated name is more known and common 
 than the actual full name. Examples are: HTTP, FTP and so on.
Yeah these are the types of things I think we should discuss, especially for the standard library before we enable this feature.
May 13
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/12/20 2:22 AM, Jonathan Marler wrote:
 
 I'd really like to see the DIP include a proposal on parameter naming 
 conventions for the standard libraries before we enable this.
 
[snip]
 3. ...
Another convention could be -- if a parameter starts with underscore, then the expectation is that you don't use named parameters with that argument. Such parameter names should always come first, and are subject to the parameter name changing without considering it to break code. If you use _xyz as a named parameter, and the name changes to _abc, that's your fault. Just an idea, in the event that we cannot find a good way to have the compiler prevent named parameter usage. -Steve
May 14
next sibling parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 14 May 2020 at 19:55:02 UTC, Steven Schveighoffer 
wrote:
 Another convention could be -- if a parameter starts with 
 underscore, then the expectation is that you don't use named 
 parameters with that argument. Such parameter names should 
 always come first, and are subject to the parameter name 
 changing without considering it to break code.

 If you use _xyz as a named parameter, and the name changes to 
 _abc, that's your fault.
+1 For those who want automatic enforcement, maybe a check for this could be added to D-Scanner?
May 14
prev sibling next sibling parent Jonathan Marler <johnnymarler gmail.com> writes:
On Thursday, 14 May 2020 at 19:55:02 UTC, Steven Schveighoffer 
wrote:
 On 5/12/20 2:22 AM, Jonathan Marler wrote:
 
 I'd really like to see the DIP include a proposal on parameter 
 naming conventions for the standard libraries before we enable 
 this.
 
[snip]
 3. ...
Another convention could be -- if a parameter starts with underscore, then the expectation is that you don't use named parameters with that argument. Such parameter names should always come first, and are subject to the parameter name changing without considering it to break code. If you use _xyz as a named parameter, and the name changes to _abc, that's your fault. Just an idea, in the event that we cannot find a good way to have the compiler prevent named parameter usage. -Steve
Yeah even if it's not enforced, a convention like that would be fine with me. We just have to get everyone to agree on the convention....which is easier said than done :)
May 14
prev sibling parent Tove <tove fransson.se> writes:
On Thursday, 14 May 2020 at 19:55:02 UTC, Steven Schveighoffer 
wrote:

 If you use _xyz as a named parameter, and the name changes to 
 _abc, that's your fault.

 Just an idea, in the event that we cannot find a good way to 
 have the compiler prevent named parameter usage.

 -Steve
Some people love Named Arguments. (They might overuse it) Some people hate Named Arguments. (They might overlook good opportunities to use it) If someone who hates named arguments creates a library, I don't really see the point of hir restricting the freedom of the developer that uses said library. The entire risk lies with the developer that loves named arguments, it should be upto that person to decide if the risk is worth it or not. That said, as much as I love named arguments, I would never use an argument starting with underscore as it's simply too ugly, it's a very effektive deterrent, even without a convention... but with the added power of the convention the risk of using it would be minimal. It's also possible that the opposite happens of what you all seem so afraid of, the library author decides to change the order of the arguments to facilitate UFCS but keeps the argument names unchanged, which saves the named argument user from breakage! I have made this kind of facilitate UFCS refactorings in my own codebase more often than changing argument names. TL;DR 1) I think _ is effective 2) Using a di is also a good solution... 3) .. or having different submodules to keep backwards compatibility akin to namespace versioning in recent C++. We have enough ways to handle this already, I'm totally with Walter on this one. Best DIP ever!
May 14
prev sibling next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Monday, 11 May 2020 at 11:37:07 UTC, Mike Parker wrote:
 [snip]
I think the arguments brought on in the previous review with respect to the API remain a concern. The feedback notes this issue, but in response the DIP author notes that if a parameter is not found then it is an error. Of course, this is the whole issue. Someone can change void foo(int x, int y, int z) {} to void foo(int x, int a, int b) {} and user code that relies on calling foo with keywords for y and z will break. I think this also connects with the feedback that the feature should be opt-in. I think the comments in the prior discussion with respect to Python's positional-only and keyword-only arguments make sense (see [1] for the PEP on this). In particular, the only change I would make to this DIP would be to make it so that keyword arguments are opt-in, such asmaking the syntax something like auto functionName(positional_only_parameters, /, positional_or_keyword_parameters) {} While python requires "/" to force positional_only this is because "positional_or_keyword_parameters" is the default. Thus, I would recommend having / to force positional_or_keyword_parameters. So for instance, you could still have void foo(int x, int a, int b) {} and only have positional arguments and no breakage if names change, or you could potentially allow keyword arguments, as in void foo(int x, /, int a, int b) {} and call it like foo(3, 2, 1); foo(3, 2, b:1); foo(3, a:2, b:1); foo(3, b:1, a:2); [1] https://www.python.org/dev/peps/pep-0570/
May 12
next sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Tuesday, 12 May 2020 at 18:57:25 UTC, jmh530 wrote:
 On Monday, 11 May 2020 at 11:37:07 UTC, Mike Parker wrote:
 [...]
I think the arguments brought on in the previous review with respect to the API remain a concern. The feedback notes this issue, but in response the DIP author notes that if a parameter is not found then it is an error. Of course, this is the whole issue. Someone can change void foo(int x, int y, int z) {} to void foo(int x, int a, int b) {} and user code that relies on calling foo with keywords for y and z will break. I think this also connects with the feedback that the feature should be opt-in. [...]
If the user uses named arguments then that is by definition opt-in. It makes no sense for the developer to opt-in for named arguments as well. I had already made my case regarding the "opt-in" part of the default and you can't opt out of it. -Alex
May 12
next sibling parent reply bachmeier <no spam.net> writes:
On Tuesday, 12 May 2020 at 21:03:34 UTC, 12345swordy wrote:

 If the user uses named arguments then that is by definition 
 opt-in. It makes no  sense for the developer to opt-in for 
 named arguments as well.

 I had already made my case regarding the "opt-in" part of the 

 default and you can't opt out of it.
I wasn't going to comment on this, but...yes, it makes perfect sense for the developer to opt in. Maybe you don't want someone calling arguments by name. Making a change like this *and* forcing it on everyone is a an argument.
May 12
parent 12345swordy <alexanderheistermann gmail.com> writes:
On Tuesday, 12 May 2020 at 22:01:00 UTC, bachmeier wrote:


 I wasn't going to comment on this, but...yes, it makes perfect 
 sense for the developer to opt in.
No, it does not make sense for the developer to opt in as the opt in process is done by the user here. You fear of code breakage due to name change still exist in this scenario, even if did make it opt in.
 Maybe you don't want someone calling arguments by name.
Which I found the reasons being brought forward by this weak at best, nonissue at worst. If you end up in a situation where you frequently chaining names of things, then you are doing something very wrong.
 Making a change like this *and* forcing it on everyone is a 
 change that belongs in D 3.0.
Nonsense. The d language already does that already via a desperation process. The most recent change is the dip 25 start being forced on developers. This isn't c++ here. Making it opt-in will kill the adaptation of said feature, as many libraries have need to be modify and recompile which will require signficant amount of time here.

 an argument.
No, the argument is there has been no apocalypse case scenario in ever sense it was introduce in 4.0.
May 12
prev sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 12 May 2020 at 21:03:34 UTC, 12345swordy wrote:
 [snip]

 If the user uses named arguments then that is by definition 
 opt-in. It makes no  sense for the developer to opt-in for 
 named arguments as well.

 I had already made my case regarding the "opt-in" part of the 

 default and you can't opt out of it.

 -Alex
The underlying worry is that the developer changes the names of the parameters and user code that depends on the names not changing breaks. When I say opt-in, I mean that the developer opts-in to let the user be able to use them. In essence, they would be acknowledging that these parameters will not have their names changed without a clear path forward. you can put the named ones at the end or you keep the positional arguments in the right place. The proposal in the DIP is more flexible, as far as I can tell. [1] https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.2/non-trailing-named-arguments
May 12
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
We already have named arguments in D since the very beginning - the struct 
initialization syntax.

Not a single person has complained about breakage when implementers changed the 
names of the struct fields.

This is similar to:

1. what happens if the implementer changes the types of the parameters?

2. what happens if the implementer changes the order of the parameters?

Then user code breaks.

If anything, this feature will motivate implementers to take some care to name 
the parameters appropriately.
May 12
next sibling parent Oraby <hatem.oraby gmail.com> writes:
On Wednesday, 13 May 2020 at 00:37:51 UTC, Walter Bright wrote:
 We already have named arguments in D since the very beginning - 
 the struct initialization syntax.

 Not a single person has complained about breakage when 
 implementers changed the names of the struct fields.

 This is similar to:

 1. what happens if the implementer changes the types of the 
 parameters?

 2. what happens if the implementer changes the order of the 
 parameters?

 Then user code breaks.

 If anything, this feature will motivate implementers to take 
 some care to name the parameters appropriately.
How about providing a migration path by adding the ability to deprecate named arguments. In such way, libraries can warn users that a parameter is now deprecated either in favor of otherparameters or for future removal. An alternative but similar approach would be to enable functions to introspect whether a named argument was called as named or not, in such way the user can provide more verbose deprecation messages without polluting function signature.
May 12
prev sibling next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 13 May 2020 at 00:37:51 UTC, Walter Bright wrote:
 We already have named arguments in D since the very beginning - 
 the struct initialization syntax.

 Not a single person has complained about breakage when 
 implementers changed the names of the struct fields.
I personally do not use this feature very much. I would expect named arguments for functions to be used significantly more.
 This is similar to:

 1. what happens if the implementer changes the types of the 
 parameters?

 2. what happens if the implementer changes the order of the 
 parameters?

 Then user code breaks.

 If anything, this feature will motivate implementers to take 
 some care to name the parameters appropriately.
One reason why python supports positional-only arguments is interacting with C. Suppose there is a C library that you generate a wrapper for automatically. At some later point, the C library changes some names of parameters. If we generate a new wrapper for D, then any place where you called these functions with named parameters would break (I believe the alternative would be to remove the names from extern(C), but I believe there are reasons why people don't usually do this). This would have an impact on people who call C from D, but the C implementer would not change their behavior based on this DIP. Alternately, suppose an implementer does want to change the name of some parameters, for whatever reason. The only thing I can think of is deprecating the old function, then eventually removing the old version and replacing it with a version with the parameter name changed. I don't see anything in the DIP that would suggest that both versions could be used at once. For instance, nothing in the DIP would suggest that the following would compile: deprecated void foo(int x, int a) {} void foo(int x, int b) {} void main() { foo(1, b:2); }
May 12
parent jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 13 May 2020 at 02:38:17 UTC, jmh530 wrote:
 [snip]
 I don't see anything in the DIP that would suggest that both 
 versions could be used at once. For instance, nothing in the 
 DIP would suggest that the following would compile:
Actually it may compile based on what it says about "function resolution is done by constructing an argument list separately for each function before testing it for matching". I'm not 100% sure though.
May 12
prev sibling next sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On Wednesday, 13 May 2020 at 00:37:51 UTC, Walter Bright wrote:
 We already have named arguments in D since the very beginning - 
 the struct initialization syntax.
The key insight! Right, we always has that.
 This is similar to:

 1. what happens if the implementer changes the types of the 
 parameters?

 2. what happens if the implementer changes the order of the 
 parameters?

 Then user code breaks.

 If anything, this feature will motivate implementers to take 
 some care to name the parameters appropriately.
May 13
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/12/20 8:37 PM, Walter Bright wrote:
 We already have named arguments in D since the very beginning - the 
 struct initialization syntax.
 
 Not a single person has complained about breakage when implementers 
 changed the names of the struct fields.
As was pointed out in the last review -- if you have structs with public member fields and you changed those names, the breakage would be more severe than just a broken initializer call: auto s = S(1, 2, 3); writeln(s.foo); // Error, no member foo, did you mean Foo? It's weird to expect anyone to complain about initializer calls over actual usage.
 This is similar to:
 
 1. what happens if the implementer changes the types of the parameters?
 
 2. what happens if the implementer changes the order of the parameters?
 
 Then user code breaks.
 
 If anything, this feature will motivate implementers to take some care 
 to name the parameters appropriately.
I agree, and I don't think this is going to make a huge problem for D. It would, however, be nice to provide a way to migrate parameter names like we have for functions (via deprecation attributes). -Steve
May 13
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 5/13/2020 7:00 AM, Steven Schveighoffer wrote:
 As was pointed out in the last review -- if you have structs with public
member 
 fields and you changed those names, the breakage would be more severe than
just 
 a broken initializer call:
 
 auto s = S(1, 2, 3);
 
 writeln(s.foo); // Error, no member foo, did you mean Foo?
I don't know about "more severe". It would just give an error that a matching function was not found, and would pretty-print the list of candidate functions. Besides, if you really don't want your users to use the parameter names, int foo(int _dkfjjiufheuehgthu, long _yer_mother_was_a_hamster, double _I_did_not_read_the_documentation); and I bet they'll get the message.
May 13
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/14/20 1:57 AM, Walter Bright wrote:
 On 5/13/2020 7:00 AM, Steven Schveighoffer wrote:
 As was pointed out in the last review -- if you have structs with 
 public member fields and you changed those names, the breakage would 
 be more severe than just a broken initializer call:

 auto s = S(1, 2, 3);

 writeln(s.foo); // Error, no member foo, did you mean Foo?
I don't know about "more severe". It would just give an error that a matching function was not found, and would pretty-print the list of candidate functions.
I guess I should have said "more common". The point is, if you change the field names, people will notice first that they can't use the field names, not that the initializer call doesn't work. I personally like named parameters, and I'm good with the struct initializer syntax as well. I just don't think that your assertion that the lack of complaints about initializer syntax breakage when people change field names is somehow proof that it won't be a problem for parameter name changes when named parameters are available. They would first complain that their usage of the structs has now broken. At the same time, I'm fine with the result that changing parameter names is going to break calling code. Just name your parameters better. My still only 2 complaints here are that there is a lack of deprecation path for parameter name changes, and that you cannot create wrapper types that forward the namedness.
 Besides, if you really don't want your users to use the parameter names,
 
      int foo(int _dkfjjiufheuehgthu, long _yer_mother_was_a_hamster, 
 double _I_did_not_read_the_documentation);
 
 and I bet they'll get the message.
I don't think they will. I think you would get at least one bug report per week that you should rename these parameters to something more intuitive. -Steve
May 14
prev sibling next sibling parent reply Arvine <arvine53738291926 gmail.com> writes:
On Thursday, 14 May 2020 at 05:57:15 UTC, Walter Bright wrote:
 Besides, if you really don't want your users to use the 
 parameter names,

     int foo(int _dkfjjiufheuehgthu, long 
 _yer_mother_was_a_hamster, double 
 _I_did_not_read_the_documentation);

 and I bet they'll get the message.
I can't tell if this is a joke or not. If that is your solution instead of adding a feature to disable named parameters on particular functions. Then please incorporate it into the DIP under "best practices" :).
May 14
parent Panke <tobias pankrath.net> writes:
On Thursday, 14 May 2020 at 18:59:03 UTC, Arvine wrote:
 On Thursday, 14 May 2020 at 05:57:15 UTC, Walter Bright wrote:
 Besides, if you really don't want your users to use the 
 parameter names,

     int foo(int _dkfjjiufheuehgthu, long 
 _yer_mother_was_a_hamster, double 
 _I_did_not_read_the_documentation);

 and I bet they'll get the message.
I can't tell if this is a joke or not. If that is your solution instead of adding a feature to disable named parameters on particular functions. Then please incorporate it into the DIP under "best practices" :).
Personally and with regard to my experience with python I don't think we need a way to disable named parameters. However forcing specific parameters to be used by name, is something I find useful. If we really cannot live without an opt-out, please use a prefix like '_' (which has a lot of precedence to mean private) and not a function parameter attribute.
May 14
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 14.05.20 07:57, Walter Bright wrote:
 
 Besides, if you really don't want your users to use the parameter names,
 
      int foo(int _dkfjjiufheuehgthu, long _yer_mother_was_a_hamster, 
 double _I_did_not_read_the_documentation);
 
 and I bet they'll get the message.
Or you can just use `int foo(int, long, double);`.
May 17
parent reply Arine <arine1283798123 gmail.com> writes:
On Sunday, 17 May 2020 at 13:25:35 UTC, Timon Gehr wrote:
 On 14.05.20 07:57, Walter Bright wrote:
 
 Besides, if you really don't want your users to use the 
 parameter names,
 
      int foo(int _dkfjjiufheuehgthu, long 
 _yer_mother_was_a_hamster, double 
 _I_did_not_read_the_documentation);
 
 and I bet they'll get the message.
Or you can just use `int foo(int, long, double);`.
Not that useful for open source code (the majority of D). Don't think I even know of or have used a single library that only provides .di files.
May 18
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 19.05.20 02:05, Arine wrote:
 On Sunday, 17 May 2020 at 13:25:35 UTC, Timon Gehr wrote:
 On 14.05.20 07:57, Walter Bright wrote:
 Besides, if you really don't want your users to use the parameter names,

      int foo(int _dkfjjiufheuehgthu, long _yer_mother_was_a_hamster, 
 double _I_did_not_read_the_documentation);

 and I bet they'll get the message.
Or you can just use `int foo(int, long, double);`.
Not that useful for open source code (the majority of D). Don't think I even know of or have used a single library that only provides .di files.
int foo(int, long, double){ return cast(int)(_param_0+_param_1+_param_2); }
May 18
parent reply Arine <arine1283798123 gmail.com> writes:
On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote:
 On 19.05.20 02:05, Arine wrote:
 On Sunday, 17 May 2020 at 13:25:35 UTC, Timon Gehr wrote:
 On 14.05.20 07:57, Walter Bright wrote:
 Besides, if you really don't want your users to use the 
 parameter names,

      int foo(int _dkfjjiufheuehgthu, long 
 _yer_mother_was_a_hamster, double 
 _I_did_not_read_the_documentation);

 and I bet they'll get the message.
Or you can just use `int foo(int, long, double);`.
Not that useful for open source code (the majority of D). Don't think I even know of or have used a single library that only provides .di files.
int foo(int, long, double){ return cast(int)(_param_0+_param_1+_param_2); }
And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".
May 18
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 19.05.20 04:35, Arine wrote:
 On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote:
 On 19.05.20 02:05, Arine wrote:
 On Sunday, 17 May 2020 at 13:25:35 UTC, Timon Gehr wrote:
 On 14.05.20 07:57, Walter Bright wrote:
 Besides, if you really don't want your users to use the parameter 
 names,

      int foo(int _dkfjjiufheuehgthu, long 
 _yer_mother_was_a_hamster, double _I_did_not_read_the_documentation);

 and I bet they'll get the message.
Or you can just use `int foo(int, long, double);`.
Not that useful for open source code (the majority of D). Don't think I even know of or have used a single library that only provides .di files.
int foo(int, long, double){     return cast(int)(_param_0+_param_1+_param_2); }
And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".
I am not sure what your point is. Are you trying to argue that the suggestion is on the same level or worse than the originally proposed int foo(int _dkfjjiufheuehgthu, long _yer_mother_was_a_hamster, double _I_did_not_read_the_documentation); ? If that is not your point, I think we have nothing to discuss.
May 19
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 19.05.20 10:01, Timon Gehr wrote:
 On 19.05.20 04:35, Arine wrote:
 On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote:
 On 19.05.20 02:05, Arine wrote:
 On Sunday, 17 May 2020 at 13:25:35 UTC, Timon Gehr wrote:
 On 14.05.20 07:57, Walter Bright wrote:
 Besides, if you really don't want your users to use the parameter 
 names,

      int foo(int _dkfjjiufheuehgthu, long 
 _yer_mother_was_a_hamster, double _I_did_not_read_the_documentation);

 and I bet they'll get the message.
Or you can just use `int foo(int, long, double);`.
Not that useful for open source code (the majority of D). Don't think I even know of or have used a single library that only provides .di files.
int foo(int, long, double){     return cast(int)(_param_0+_param_1+_param_2); }
And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".
I am not sure what your point is. Are you trying to argue that the suggestion is on the same level or worse than the originally proposed int foo(int _dkfjjiufheuehgthu, long _yer_mother_was_a_hamster, double _I_did_not_read_the_documentation); ? If that is not your point, I think we have nothing to discuss.
Actually, even if that is your point, I don't think we will reach an agreement, nor would it be important to do so.
May 19
prev sibling parent reply Arine <arine1283798123 gmail.com> writes:
On Tuesday, 19 May 2020 at 08:01:09 UTC, Timon Gehr wrote:
 On 19.05.20 04:35, Arine wrote:
 On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote:
 On 19.05.20 02:05, Arine wrote:
 On Sunday, 17 May 2020 at 13:25:35 UTC, Timon Gehr wrote:
 On 14.05.20 07:57, Walter Bright wrote:
 Besides, if you really don't want your users to use the 
 parameter names,

      int foo(int _dkfjjiufheuehgthu, long 
 _yer_mother_was_a_hamster, double 
 _I_did_not_read_the_documentation);

 and I bet they'll get the message.
Or you can just use `int foo(int, long, double);`.
Not that useful for open source code (the majority of D). Don't think I even know of or have used a single library that only provides .di files.
int foo(int, long, double){     return cast(int)(_param_0+_param_1+_param_2); }
And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".
I am not sure what your point is. Are you trying to argue that the suggestion is on the same level or worse than the originally proposed int foo(int _dkfjjiufheuehgthu, long _yer_mother_was_a_hamster, double _I_did_not_read_the_documentation); ? If that is not your point, I think we have nothing to discuss.
Both are equally as bad in terms of readability. One is worse because it uses an implementation detail that can change at any time.
May 19
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Wednesday, 20 May 2020 at 02:09:27 UTC, Arine wrote:
 On Tuesday, 19 May 2020 at 08:01:09 UTC, Timon Gehr wrote:
 On 19.05.20 04:35, Arine wrote:
 On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote:
 [...]
And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".
I am not sure what your point is. Are you trying to argue that the suggestion is on the same level or worse than the originally proposed int foo(int _dkfjjiufheuehgthu, long _yer_mother_was_a_hamster, double _I_did_not_read_the_documentation); ? If that is not your point, I think we have nothing to discuss.
Both are equally as bad in terms of readability. One is worse because it uses an implementation detail that can change at any time.
So if the implementation detail is standardized, would you still object to this? -Alex
May 19
parent reply Arine <arine1283798123 gmail.com> writes:
On Wednesday, 20 May 2020 at 03:04:13 UTC, 12345swordy wrote:
 On Wednesday, 20 May 2020 at 02:09:27 UTC, Arine wrote:
 On Tuesday, 19 May 2020 at 08:01:09 UTC, Timon Gehr wrote:
 On 19.05.20 04:35, Arine wrote:
 On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote:
 [...]
And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".
I am not sure what your point is. Are you trying to argue that the suggestion is on the same level or worse than the originally proposed int foo(int _dkfjjiufheuehgthu, long _yer_mother_was_a_hamster, double _I_did_not_read_the_documentation); ? If that is not your point, I think we have nothing to discuss.
Both are equally as bad in terms of readability. One is worse because it uses an implementation detail that can change at any time.
So if the implementation detail is standardized, would you still object to this? -Alex
Both methods are terrible. A pull request that used either method in phobos would be rightfully rejected today. It doesn't bode well when such a destructive practice is suggested by the creator of a language, and then they completely fall silent from the discussion. I hope he doesn't have have the same holier than though mindset as that other individual that clearly stated they don't care about having any kind of discussion on the subject at all. That's fine by me, it's clear as night and day to me. Practicality seems to be going out the door lately anyways.
May 20
next sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Wednesday, 20 May 2020 at 20:01:51 UTC, Arine wrote:
 On Wednesday, 20 May 2020 at 03:04:13 UTC, 12345swordy wrote:
 On Wednesday, 20 May 2020 at 02:09:27 UTC, Arine wrote:
 On Tuesday, 19 May 2020 at 08:01:09 UTC, Timon Gehr wrote:
 On 19.05.20 04:35, Arine wrote:
 On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote:
 [...]
And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".
I am not sure what your point is. Are you trying to argue that the suggestion is on the same level or worse than the originally proposed int foo(int _dkfjjiufheuehgthu, long _yer_mother_was_a_hamster, double _I_did_not_read_the_documentation); ? If that is not your point, I think we have nothing to discuss.
Both are equally as bad in terms of readability. One is worse because it uses an implementation detail that can change at any time.
So if the implementation detail is standardized, would you still object to this? -Alex
Both methods are terrible. A pull request that used either method in phobos would be rightfully rejected today. It doesn't bode well when such a destructive practice is suggested by the creator of a language, and then they completely fall silent from the discussion. I hope he doesn't have have the same holier than though mindset as that other individual that clearly stated they don't care about having any kind of discussion on the subject at all. That's fine by me, it's clear as night and day to me. Practicality seems to be going out the door lately anyways.
void fun(int,int) _paramater[0] alias x; _paramater[1] alias y; } I don't see anything "destructive" about this, given that we have the alias feature. -Alex
May 20
parent Arine <arine1283798123 gmail.com> writes:
On Thursday, 21 May 2020 at 00:35:21 UTC, 12345swordy wrote:
 On Wednesday, 20 May 2020 at 20:01:51 UTC, Arine wrote:
 On Wednesday, 20 May 2020 at 03:04:13 UTC, 12345swordy wrote:
 On Wednesday, 20 May 2020 at 02:09:27 UTC, Arine wrote:
 On Tuesday, 19 May 2020 at 08:01:09 UTC, Timon Gehr wrote:
 On 19.05.20 04:35, Arine wrote:
 On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote:
 [...]
And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".
I am not sure what your point is. Are you trying to argue that the suggestion is on the same level or worse than the originally proposed int foo(int _dkfjjiufheuehgthu, long _yer_mother_was_a_hamster, double _I_did_not_read_the_documentation); ? If that is not your point, I think we have nothing to discuss.
Both are equally as bad in terms of readability. One is worse because it uses an implementation detail that can change at any time.
So if the implementation detail is standardized, would you still object to this? -Alex
Both methods are terrible. A pull request that used either method in phobos would be rightfully rejected today. It doesn't bode well when such a destructive practice is suggested by the creator of a language, and then they completely fall silent from the discussion. I hope he doesn't have have the same holier than though mindset as that other individual that clearly stated they don't care about having any kind of discussion on the subject at all. That's fine by me, it's clear as night and day to me. Practicality seems to be going out the door lately anyways.
void fun(int,int) _paramater[0] alias x; _paramater[1] alias y; } I don't see anything "destructive" about this, given that we have the alias feature. -Alex
Editors that use the signature to get parameter names to help while you are writing code. It will have to be able to identify that pattern, and realistically you could define a parameter multiple times or not at the beginning of the function. That also reminds me of the old C style function declarations, where the type and name were separated. double foo( a , real ) double *real; int a; { } Not exactly the same, but it most definitely is a step backwards. Then you also get into the problem of documentation for parameters. It is an overall net loss that just creates more problems of it's own. It'd make more sense to fix the problem here with named parameters, than to pass down the problem to something else.
May 21
prev sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 20 May 2020 at 20:01:51 UTC, Arine wrote:
 On Wednesday, 20 May 2020 at 03:04:13 UTC, 12345swordy wrote:
 So if the implementation detail is standardized, would you 
 still object to this?

 -Alex
Both methods are terrible. A pull request that used either method in phobos would be rightfully rejected today. It doesn't bode well when such a destructive practice is suggested by the creator of a language, and then they completely fall silent from the discussion. I hope he doesn't have have the same holier than though mindset as that other individual that clearly stated they don't care about having any kind of discussion on the subject at all. That's fine by me, it's clear as night and day to me. Practicality seems to be going out the door lately anyways.
Here's a method that works using existing language features and doesn't rely on implementation details that aren't part of the language spec: int foo(int, int) { static if (is(typeof(__traits(parent, {})) params == __parameters)) { mixin("alias x = ", __traits(identifier, params[0..1]), ";"); mixin("alias y = ", __traits(identifier, params[1..2]), ";"); } return x + y; } unittest { assert(foo(1, 2) == 3); } It's pretty ugly, but the ugliness is hidden entirely inside the function's implementation. And the whole static if block could be factored out into a mixin if you wanted to re-use it in multiple functions.
May 20
parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 21 May 2020 at 01:07:36 UTC, Paul Backus wrote:
 It's pretty ugly, but the ugliness is hidden entirely inside 
 the function's implementation. And the whole static if block 
 could be factored out into a mixin if you wanted to re-use it 
 in multiple functions.
To wit: mixin template parameterAliases(names...) { static if (is(typeof(__traits(parent, {})) params == __parameters)) static foreach (i, name; names) mixin("alias ", name, " = ", __traits(identifier, params[i..i+1]), ";"); } int foo(int, int) { mixin parameterAliases!("x", "y"); return x + y; }
May 21
prev sibling next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Tuesday, May 12, 2020 6:37:51 PM MDT Walter Bright via Digitalmars-d wrote:
 We already have named arguments in D since the very beginning - the struct
 initialization syntax.

 Not a single person has complained about breakage when implementers changed
 the names of the struct fields.
I have _never_ used the struct initialization syntax, and I'm not sure that I've ever actually seen it used in any code that I've worked on. In my experience, it's also usually the case that structs aren't POD types and don't expose their members, making it so that most structs wouldn't work with the struct initialization syntax anyway (and I'm that much less likely to have a POD struct in a library, because I don't want to have to deal with worrying about breakage caused by name changes). I think that it's quite safe to say that whatever impact struct initialization syntax has had is not at all on the same level that named arguments would have. Personally, I wish that the struct initialization syntax didn't exist in D, but at least it seems to have relatively few people using it, whereas there are enough people who seem to like the idea of named arguments that I expect that once they're in, some people will start using them all over the place like they were writing python rather than D.
 This is similar to:

 1. what happens if the implementer changes the types of the parameters?

 2. what happens if the implementer changes the order of the parameters?

 Then user code breaks.

 If anything, this feature will motivate implementers to take some care to
 name the parameters appropriately.
I don't want to have yet more stuff added to a function's API which I then have to worry about whether I can change without breaking existing code. We already have enough such problems to worry about without adding more. And I don't want to have to deal with bikeshedding over parameter names like we too often have to deal with with function names and type names. From the perspective of someone writing libraries for others to use, I see named arguments as nothing but trouble. And as a user, I don't see them as adding any real benefit except in cases where functions have too many parameters anyway and probably should have been designed differently. Given that you're the one writing this DIP and that Atila has been in favor of named arguments for years, I expect that I'm going to be stuck dealing with named arguments in D at some point here, but I'm sure not happy about the idea. It's a pythonism that IMHO just makes code worse - especially from the perspective of having to worry about code breakage and bikeshedding. And the fact that there are other things that you already have to worry about breaking when changing function signatures doesn't mean that adding yet more things that you have to worry about breaking isn't making things worse. - Jonathan M Davis
May 15
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 5/15/2020 12:56 PM, Jonathan M Davis wrote:
 I don't want to have yet more stuff added to a function's API which I then
 have to worry about whether I can change without breaking existing code. We
 already have enough such problems to worry about without adding more. And I
 don't want to have to deal with bikeshedding over parameter names like we
 too often have to deal with with function names and type names.
I almost never change a parameter name. I also can't see myself using named parameters very often. Nobody says anyone has to used them.
 From the
 perspective of someone writing libraries for others to use, I see named
 arguments as nothing but trouble. And as a user, I don't see them as adding
 any real benefit except in cases where functions have too many parameters
 anyway and probably should have been designed differently.
I'd like to have them just so we can get rid of that Flag!"Name".yes template abomination: https://dlang.org/phobos/std_typecons.html#Flag
 Given that you're the one writing this DIP and that Atila has been in favor
 of named arguments for years, I expect that I'm going to be stuck dealing
 with named arguments in D at some point here,
Probably true.
 but I'm sure not happy about the idea.
Sorry about that. But I suspect you'll like it better than that awful `struct Yes`: https://dlang.org/phobos/std_typecons.html#Yes
May 16
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Saturday, May 16, 2020 2:57:06 PM MDT Walter Bright via Digitalmars-d 
wrote:
 Sorry about that. But I suspect you'll like it better than that awful
 `struct Yes`:

 https://dlang.org/phobos/std_typecons.html#Yes
Marginally. Personally, I've always been of the opinion that just using true and false directly works well enough, but I seem to be in the minority around here in thinking that. Either way, while FlagName.yes is bad enough, Yes.flagName is completely backwards and ugly. So, it certainly won't hurt my feelings any if that goes away because of this. - Jonathan M Davis
May 16
parent Walter Bright <newshound2 digitalmars.com> writes:
On 5/16/2020 2:14 PM, Jonathan M Davis wrote:
 Marginally. Personally, I've always been of the opinion that just using true
 and false directly works well enough, but I seem to be in the minority
 around here in thinking that. Either way, while FlagName.yes is bad enough,
 Yes.flagName is completely backwards and ugly. So, it certainly won't hurt
 my feelings any if that goes away because of this.
Glad to see we can agree on something!
May 16
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2020-05-15 21:56, Jonathan M Davis wrote:

 I have _never_ used the struct initialization syntax, and I'm not sure that
 I've ever actually seen it used in any code that I've worked on. In my
 experience, it's also usually the case that structs aren't POD types and
 don't expose their members
I guess it depends on what kind of code you write. It's super useful when implementing or using web APIs that use JSON. When doing that I have one function per API endpoint, one struct for the request and one for the response. For those cases it's only POD structs with all members being public. Just the other day I had to interface with the Datadog API. One of the API endpoints expects a JSON body with the following attributes: struct Request { static struct Time { string from; string timezone = "UTC"; string to; } string index = "main"; int limit; string query; string sort = "asc"; string startAt; Time time; } The only attributes that are required are "query" and "time". With the struct initialization syntax it looks very nice: const Request request = { query: "foobar", time: { from: "now-10s", to: "now" } }; Without the above syntax I would need to either use the constructor syntax, which makes it very difficult to understand which attributes the values belong to. Or using regular field assignment, but then the variable cannot be const. Request request; // cannot be const request.query = "foobar"; request.time.from = "now-10s"; request.time.to = "now"; The above example could use the `with` statement to shorten the code a bit. Then just serialize the struct to JSON and pass as the body of the HTTP request. -- /Jacob Carlborg
May 17
prev sibling parent reply Arine <arine1283798123 gmail.com> writes:
On Wednesday, 13 May 2020 at 00:37:51 UTC, Walter Bright wrote:
 We already have named arguments in D since the very beginning - 
 the struct initialization syntax.

 Not a single person has complained about breakage when 
 implementers changed the names of the struct fields.
There's a simple workaround; it can even be deprecated! struct A { int a; } // renamed a -> b struct A { int b; deprecated alias a = b; } I feel like this was mentioned in the last thread too. I don't see the point in going around in circles if you aren't going to learn anything from it.
 This is similar to:

 1. what happens if the implementer changes the types of the 
 parameters?
It can be deprecated and overloaded at the same time.
 2. what happens if the implementer changes the order of the 
 parameters?
See above. If they are the same type, then it probably isn't a meaningful change and can just be entirely avoided. Really if an implementer changes parameters around of the same type then that's them purposefully being malicious or they just don't give a shit.
 Then user code breaks.

 If anything, this feature will motivate implementers to take 
 some care to name the parameters appropriately.
All of these have ways to have the new method and the old method existing in the codebase at the same time, with the old method being deprecated. It's not equivalent to the current DIPs suggested implementation.
May 15
next sibling parent reply matheus <matheus gmail.com> writes:
On Friday, 15 May 2020 at 23:45:46 UTC, Arine wrote:
 On Wednesday, 13 May 2020 at 00:37:51 UTC, Walter Bright wrote:
...
 2. what happens if the implementer changes the order of the 
 parameters?
See above. If they are the same type, then it probably isn't a meaningful change and can just be entirely avoided. Really if an implementer changes parameters around of the same type then that's them purposefully being malicious or they just don't give a shit.
That's true. In fact who would do that? Who would change the order of parameters after a resource/feature is already exposed? For me this is pure suicide, and I wouldn't trust in this resource anymore. At least in some common and good libraries, APIs, SDKs or whatever I never saw this happen. Matheus.
May 16
parent Paolo Invernizzi <paolo.invernizzi gmail.com> writes:
On Saturday, 16 May 2020 at 13:30:34 UTC, matheus wrote:
 On Friday, 15 May 2020 at 23:45:46 UTC, Arine wrote:
 On Wednesday, 13 May 2020 at 00:37:51 UTC, Walter Bright wrote:
...
 2. what happens if the implementer changes the order of the 
 parameters?
See above. If they are the same type, then it probably isn't a meaningful change and can just be entirely avoided. Really if an implementer changes parameters around of the same type then that's them purposefully being malicious or they just don't give a shit.
That's true. In fact who would do that? Who would change the order of parameters after a resource/feature is already exposed? For me this is pure suicide, and I wouldn't trust in this resource anymore. At least in some common and good libraries, APIs, SDKs or whatever I never saw this happen. Matheus.
Happened sometimes in Phobos, to put the range as a first parameter to a function, just to allow pipelining. The solution was to add another function with the arranged parameters order. So, sometime it happens...
May 17
prev sibling parent 12345swordy <alexanderheistermann gmail.com> writes:
On Friday, 15 May 2020 at 23:45:46 UTC, Arine wrote:
  Really if
 an implementer changes parameters around of the same type then 
 that's them purposefully being malicious or they just don't 
 give a ****.
You can make the same remark when it comes to changing parameter names. -Alex
May 16
prev sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 12 May 2020 at 18:57:25 UTC, jmh530 wrote:
 On Monday, 11 May 2020 at 11:37:07 UTC, Mike Parker wrote:
 [snip]
I think the comments in the prior discussion with respect to Python's positional-only and keyword-only arguments make sense (see [1] for the PEP on this). In particular, the only change I would make to this DIP would be to make it so that keyword arguments are opt-in, such asmaking the syntax something like auto functionName(positional_only_parameters, /, positional_or_keyword_parameters) {} [snip]
Given the recent discussions, I am reconsidering what I said above. First, Seb's extern(D, argNames) (or other bikeshedded name) seems worth including. It would mean that keyword_only_parameters could potentially be emulated for people who need that. extern(D, argNames) wouldn't apply to positional_only_parameters. However, I have reconsidered keeping positional-only as the default. Instead, I would have what this DIP suggests as the default, as in auto functionName(positional_or_keyword_parameters) {} However, I would also allow an opt-in for positional only parameters, so that the full syntax would be auto functionName(positional_only_parameters, /, positional_or_keyword_parameters) {} Recall Paul's argument (that Walter approved of) that there should be only one set of rules and we already have the struct initialization rules. From the perspective of these edits, the struct initialization rules would be the special case of these for wen there are no positional_only_parameters. Only one set of rules is needed, but you add the ability to handle deprecations and allow positional_only_parameters without resorting to hacks or long, ugly names.
May 14
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On Monday, 11 May 2020 at 11:37:07 UTC, Mike Parker wrote:
 This is the discussion thread for the Final Review of DIP 1030, 
 "Named Arguments":

 https://github.com/dlang/DIPs/blob/7d114c93edb02d8fc4b05f0716bdb6057905fec2/DIPs/DIP1030.md
I see people mentioning wrapper overloads to enable deprecation of old parameter names. But why not just support this in code? Something like: ```D void foo ( deprecated("x_val") int x, deprecated("y_val") int y) { } ``` And then the compiler emits warnings if you use `foo(x_val : 10, y_val : 20)`.
May 12
next sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 13 May 2020 at 06:11:46 UTC, Andrej Mitrovic wrote:
 [snip]

 I see people mentioning wrapper overloads to enable deprecation 
 of old parameter names. But why not just support this in code?

 Something like:

 ```D
 void foo ( deprecated("x_val") int x,  deprecated("y_val") int 
 y)
 {
 }
 ```

 And then the compiler emits warnings if you use `foo(x_val : 
 10, y_val : 20)`.
So there wouldn't be a warning if they call foo(10, 20)? That would mean the user couldn't provide an alternate `void foo(int x_new_name, int y_new_name) {}` until the deprecation period ends. If you make it so that a function with deprecated names can only be called with the old names specifically, then this would free the implementers up to write a separate function with new names. Any call like foo(10, 20) wouldn't change if they supply the new function, but a call like foo(x_val: 10, y_val: 20) would get a deprecation message. Another way to think of it would be that functions without deprecated parameter names have higher priority in the overload set than ones with deprecated names. I think this would resolve my concern with deprecations, if Walter goes for it.
May 13
prev sibling parent reply Seb <seb wilzba.ch> writes:
On Wednesday, 13 May 2020 at 06:11:46 UTC, Andrej Mitrovic wrote:
 On Monday, 11 May 2020 at 11:37:07 UTC, Mike Parker wrote:
 This is the discussion thread for the Final Review of DIP 
 1030, "Named Arguments":

 https://github.com/dlang/DIPs/blob/7d114c93edb02d8fc4b05f0716bdb6057905fec2/DIPs/DIP1030.md
I see people mentioning wrapper overloads to enable deprecation of old parameter names. But why not just support this in code? Something like: ```D void foo ( deprecated("x_val") int x, deprecated("y_val") int y) { } ``` And then the compiler emits warnings if you use `foo(x_val : 10, y_val : 20)`.
What happens if a) you change the argument names twice b) you re-order the argument names c) you want to change the name and type tl;dr: I believe it would be more general-purpose if the compiler would allow this: ``` void foo(int x, int y) { ... } deprecated extern(D, argNames) void foo(int xVal, int yVal) { ... } ``` And then the compiler prefers non-deprecated overload if it's not explicitly requested. Though that would require including the argument names into the function mangling of the deprecated which is requested here with the fictional extern (D, argNames).
May 13
parent jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 13 May 2020 at 19:24:46 UTC, Seb wrote:
 [snip]
 ```
 void foo(int x, int y) { ... }

  deprecated extern(D, argNames)
 void foo(int xVal, int yVal) { ... }
 ```

 [snip]
Even better!
May 13
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2020-05-11 13:37, Mike Parker wrote:
 This is the discussion thread for the Final Review of DIP 1030, "Named 
 Arguments":
 
 https://github.com/dlang/DIPs/blob/7d114c93edb02d8fc4b05f0716bdb6057905
ec2/DIPs/DIP1030.md 
Regarding renaming parameters will break the API. Swift supports giving a different name which are used locally: func copy(_ source: String, to destination: String) Should be called like this: copy("foo", to: "bar") `_` indicates that the argument can not be named when calling the function. `to` is the name that is used when calling the function. `source` and `destination` are the names used locally in the implementation of the function. This allows to rename a parameter (the local name) without breaking the API. -- /Jacob Carlborg
May 13
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 13 May 2020 at 07:55:33 UTC, Jacob Carlborg wrote:
 Regarding renaming parameters will break the API. Swift 
 supports giving a different name which are used locally:

 func copy(_ source: String, to destination: String)

 Should be called like this:

 copy("foo", to: "bar")

 `_` indicates that the argument can not be named when calling 
 the function. `to` is the name that is used when calling the 
 function. `source` and `destination` are the names used locally 
 in the implementation of the function.

 This allows to rename a parameter (the local name) without 
 breaking the API.
Worth noting that this can also be done in D using local alias declarations: void copy(const(char)[] _, char[] to) { alias source = _; alias destination = to; // etc. } Granted, the D compiler will not actually stop anyone from giving the first argument by name, but it's hard to imagine why anyone would want to.
May 13
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/13/20 9:15 AM, Paul Backus wrote:
 On Wednesday, 13 May 2020 at 07:55:33 UTC, Jacob Carlborg wrote:
 Regarding renaming parameters will break the API. Swift supports 
 giving a different name which are used locally:

 func copy(_ source: String, to destination: String)

 Should be called like this:

 copy("foo", to: "bar")

 `_` indicates that the argument can not be named when calling the 
 function. `to` is the name that is used when calling the function. 
 `source` and `destination` are the names used locally in the 
 implementation of the function.

 This allows to rename a parameter (the local name) without breaking 
 the API.
Worth noting that this can also be done in D using local alias declarations: void copy(const(char)[] _, char[] to) {     alias source = _;     alias destination = to;     // etc. } Granted, the D compiler will not actually stop anyone from giving the first argument by name, but it's hard to imagine why anyone would want to.
Note that in Swift, _ means "unnamed parameter", it's not an actual name. So we can't really do what it can do: copy(_ source: String, _ destination: String) could be called like: copy("foo", "bar") The equivalent in D would have multiple parameter names as _ which isn't allowed. Hm... an interesting proposition, we could provide a way to disallow using names if the name starts with something like _: void foo(int _x) { alias x = _x; ... } foo(_x: 1); // Error foo(1); // OK It might be better than having to use .di files to prevent parameter-name based calling. -Steve
May 13
parent Luhrel <lucien.perregaux gmail.com> writes:
On Wednesday, 13 May 2020 at 13:56:26 UTC, Steven Schveighoffer 
wrote:
 Hm... an interesting proposition, we could provide a way to 
 disallow using names if the name starts with something like _:

 void foo(int _x)
 {
    alias x = _x;
    ...
 }

 foo(_x: 1); // Error
 foo(1); // OK

 It might be better than having to use .di files to prevent 
 parameter-name based calling.

 -Steve
What about a required (or a better name) that will force the user to use the named argument ? --- void copy(string src, required string dest) {} copy(source: "myfile", "yourfile"); // Error: Missing named argument `dest:` before `"yourfile"` copy("myfile", dest: "yourfile"); // Ok --- Also, should named args, if used, always be spelt correctly ? --- void anotherCopy(string src, required destination: string dst) {} void anotherCopy("file1", dest: "file2"): // Error: Named argument `dest:` must be spelt `destination:` void anotherCopy("file1", destination: "file2"); // Ok ---
May 22
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 5/13/2020 12:55 AM, Jacob Carlborg wrote:
 Regarding renaming parameters will break the API. Swift supports giving a 
 different name which are used locally:
 
 func copy(_ source: String, to destination: String)
 
 Should be called like this:
 
 copy("foo", to: "bar")
 
 `_` indicates that the argument can not be named when calling the function.
In D, we do: void copy(string, string destination);
May 13
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/13/20 3:30 PM, Walter Bright wrote:
 On 5/13/2020 12:55 AM, Jacob Carlborg wrote:
 Regarding renaming parameters will break the API. Swift supports 
 giving a different name which are used locally:

 func copy(_ source: String, to destination: String)

 Should be called like this:

 copy("foo", to: "bar")

 `_` indicates that the argument can not be named when calling the 
 function.
In D, we do:    void copy(string, string destination);
And how does the implementation of copy use that first parameter? -Steve
May 13
next sibling parent reply Jonathan Marler <johnnymarler gmail.com> writes:
On Wednesday, 13 May 2020 at 19:31:24 UTC, Steven Schveighoffer 
wrote:
 On 5/13/20 3:30 PM, Walter Bright wrote:
 On 5/13/2020 12:55 AM, Jacob Carlborg wrote:
 Regarding renaming parameters will break the API. Swift 
 supports giving a different name which are used locally:

 func copy(_ source: String, to destination: String)

 Should be called like this:

 copy("foo", to: "bar")

 `_` indicates that the argument can not be named when calling 
 the function.
In D, we do:    void copy(string, string destination);
And how does the implementation of copy use that first parameter? -Steve
I found a way: void copy(string, string destination) { alias source = _param_0; } I didn't realize you could do this till now but this allows functions to "opt-out" of using named parameters. We may want to consider using this pattern throughout phobos/druntime when we want want to prevent parameter names from being apart of the API.
May 13
next sibling parent reply Panke <tobias pankrath.net> writes:
On Wednesday, 13 May 2020 at 19:44:32 UTC, Jonathan Marler wrote:
 I found a way:

 void copy(string, string destination)
 {
     alias source = _param_0;
 }

 I didn't realize you could do this till now but this allows 
 functions to "opt-out" of using named parameters.  We may want 
 to consider using this pattern throughout phobos/druntime when 
 we want want to prevent parameter names from being apart of the 
 API.
Makes the documentation worse though.
May 13
parent reply Jonathan Marler <johnnymarler gmail.com> writes:
On Wednesday, 13 May 2020 at 19:48:58 UTC, Panke wrote:
 On Wednesday, 13 May 2020 at 19:44:32 UTC, Jonathan Marler 
 wrote:
 I found a way:

 void copy(string, string destination)
 {
     alias source = _param_0;
 }

 I didn't realize you could do this till now but this allows 
 functions to "opt-out" of using named parameters.  We may want 
 to consider using this pattern throughout phobos/druntime when 
 we want want to prevent parameter names from being apart of 
 the API.
Makes the documentation worse though.
If it makes the documentation worse then it means the parameter names were helpful to the API, in which case you wouldn't do this. The "copy" function isn't a good example because the "source" and "destination" parameter names are actually helpful to include.
May 13
next sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 13 May 2020 at 19:55:20 UTC, Jonathan Marler wrote:
 [snip]
 Makes the documentation worse though.
If it makes the documentation worse then it means the parameter names were helpful to the API, in which case you wouldn't do this. The "copy" function isn't a good example because the "source" and "destination" parameter names are actually helpful to include.
I think the broader point though is that if the technique shouldn't be used on `copy` than it isn't a general solution for interacting with someone else's library. What about an attribute? Perhaps positionalOnly. It's ugly, but at least it's self-documenting. Using a named parameter with an positionalOnly parameter would result in an error. This makes positional opt-in and used rarely.
May 13
prev sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, May 13, 2020 1:55:20 PM MDT Jonathan Marler via Digitalmars-d 
wrote:
 On Wednesday, 13 May 2020 at 19:48:58 UTC, Panke wrote:
 On Wednesday, 13 May 2020 at 19:44:32 UTC, Jonathan Marler

 wrote:
 I found a way:

 void copy(string, string destination)
 {

     alias source = _param_0;

 }

 I didn't realize you could do this till now but this allows
 functions to "opt-out" of using named parameters.  We may want
 to consider using this pattern throughout phobos/druntime when
 we want want to prevent parameter names from being apart of
 the API.
Makes the documentation worse though.
If it makes the documentation worse then it means the parameter names were helpful to the API, in which case you wouldn't do this. The "copy" function isn't a good example because the "source" and "destination" parameter names are actually helpful to include.
Just because having the parameter names in the documentation helps make the documentation clearer doesn't mean that it's desirable to actually have the parameter names be part of the API. Personally, I think that the documentation is much clearer and cleaner if the parameter names are in it, but I have zero interest in parameters names actually being part of the API where they then will cause code breakage if changed and risk causing even more bike-shedding arguments. I hate the whole idea of this DIP (and that of any other DIP that adds named arguments), but since Walter now seems to be on board wtih the idea, and I know that Atila has been for years, I expect that I'm out of luck, and I'm going to be stuck with some version of them in the language. If it weren't for how it affected the documentation, I almost certainly would stop naming any parameters on public functions and would use a "trick" like this one, though of course, that wouldn't fix it so that I wouldn't have to put up with named arguments in code just make it so that I wouldn't have to deal with how changing parameter names would break the code of anyone using any libraries I write. - Jonathan M Davis
May 15
prev sibling next sibling parent Jonathan Marler <johnnymarler gmail.com> writes:
On Wednesday, 13 May 2020 at 19:44:32 UTC, Jonathan Marler wrote:
 On Wednesday, 13 May 2020 at 19:31:24 UTC, Steven Schveighoffer 
 wrote:
 On 5/13/20 3:30 PM, Walter Bright wrote:
 On 5/13/2020 12:55 AM, Jacob Carlborg wrote:
 Regarding renaming parameters will break the API. Swift 
 supports giving a different name which are used locally:

 func copy(_ source: String, to destination: String)

 Should be called like this:

 copy("foo", to: "bar")

 `_` indicates that the argument can not be named when 
 calling the function.
In D, we do:    void copy(string, string destination);
And how does the implementation of copy use that first parameter? -Steve
I found a way: void copy(string, string destination) { alias source = _param_0; } I didn't realize you could do this till now but this allows functions to "opt-out" of using named parameters. We may want to consider using this pattern throughout phobos/druntime when we want want to prevent parameter names from being apart of the API.
I've created a PR to use this pattern in some of the functions in std.math: https://github.com/dlang/phobos/pull/7480 Let's see what the community thinks about this pattern and if it should be adopted by druntime/phobos in anticipation of enabling named parameters.
May 13
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/13/20 3:44 PM, Jonathan Marler wrote:

 I found a way:
 
 void copy(string, string destination)
 {
      alias source = _param_0;
 }
 
 I didn't realize you could do this till now but this allows functions to 
 "opt-out" of using named parameters.  We may want to consider using this 
 pattern throughout phobos/druntime when we want want to prevent 
 parameter names from being apart of the API.
 
That is an implementation detail, and not a spec feature. It would have to be properly defined for it to be a sufficient workaround. Also, there is no guarantee that with this DIP: copy(_param_0: "foo", destination: "bar") doesn't work. There would have to be. -Steve
May 13
parent Jonathan Marler <johnnymarler gmail.com> writes:
On Wednesday, 13 May 2020 at 20:42:32 UTC, Steven Schveighoffer 
wrote:
 On 5/13/20 3:44 PM, Jonathan Marler wrote:

 I found a way:
 
 void copy(string, string destination)
 {
      alias source = _param_0;
 }
 
 I didn't realize you could do this till now but this allows 
 functions to "opt-out" of using named parameters.  We may want 
 to consider using this pattern throughout phobos/druntime when 
 we want want to prevent parameter names from being apart of 
 the API.
 
That is an implementation detail, and not a spec feature. It would have to be properly defined for it to be a sufficient workaround.
Darn
 Also, there is no guarantee that with this DIP:

 copy(_param_0: "foo", destination: "bar")

 doesn't work. There would have to be.
This one isn't as concerning to me.
May 13
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 5/13/2020 12:31 PM, Steven Schveighoffer wrote:
 On 5/13/20 3:30 PM, Walter Bright wrote:
 In D, we do:
     void copy(string, string destination);
And how does the implementation of copy use that first parameter?
----- test.di ----- void copy(string, string destination); ----- test.d ------ void copy(string src, string destination) { ... }
May 13
next sibling parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Thursday, 14 May 2020 at 05:19:21 UTC, Walter Bright wrote:
 On 5/13/2020 12:31 PM, Steven Schveighoffer wrote:
 On 5/13/20 3:30 PM, Walter Bright wrote:
 In D, we do:
     void copy(string, string destination);
And how does the implementation of copy use that first parameter?
----- test.di ----- void copy(string, string destination); ----- test.d ------ void copy(string src, string destination) { ... }
Since .di files quite rare in D, compared to C and C++, can we also support the following: ----- test.d ------ // originally written as `void copy(string src, string dst)`: void copy(string source, string destination) { ... } // `copy` function author decided to improve the function signature, // by not using abbreviated names. To prevent breaking changes they // add a deprecated declaration: deprecated("Parameters renamed: `src` -> `source` | `dst` -> `destination`") void copy(string src, string dst); // However the author made a mistake and actually wrote: // void copy(string source, string distinasion) // Being extra careful about their users, the author adds another // deprecated declaration: deprecate("`distinasion` was renamed to `destination` to correct typo") void copy(string source, string distinasion); ----- old_time_user.d ------ void main() { // keeps working, though emits a deprecation message: // Parameters renamed: `src` -> `source` | `dst` -> `destination` copy(src: "/some/path", dst: "/another/path"); } ----- new_user.d ------ void main() { // works with no deprecation messages copy(source: "/some/path", destination: "/another/path"); } ----- conservative_user.d ------ void main() { // works without ambiguity error copy("/some/path", "/another/path"); } Since parameter names are not going to be part of the name managing, I propose that the compiler merges function declarations that produce the same mangled name in order to not emit ambiguity errors.
May 14
parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Thursday, 14 May 2020 at 11:56:41 UTC, Petar Kirov 
[ZombineDev] wrote:
 On Thursday, 14 May 2020 at 05:19:21 UTC, Walter Bright wrote:
 On 5/13/2020 12:31 PM, Steven Schveighoffer wrote:
 On 5/13/20 3:30 PM, Walter Bright wrote:
 In D, we do:
     void copy(string, string destination);
And how does the implementation of copy use that first parameter?
----- test.di ----- void copy(string, string destination); ----- test.d ------ void copy(string src, string destination) { ... }
Since .di files quite rare in D, compared to C and C++, can we also support the following: ----- test.d ------ // originally written as `void copy(string src, string dst)`: void copy(string source, string destination) { ... } // `copy` function author decided to improve the function signature, // by not using abbreviated names. To prevent breaking changes they // add a deprecated declaration: deprecated("Parameters renamed: `src` -> `source` | `dst` -> `destination`") void copy(string src, string dst); // However the author made a mistake and actually wrote: // void copy(string source, string distinasion) // Being extra careful about their users, the author adds another // deprecated declaration: deprecate("`distinasion` was renamed to `destination` to correct typo") void copy(string source, string distinasion); ----- old_time_user.d ------ void main() { // keeps working, though emits a deprecation message: // Parameters renamed: `src` -> `source` | `dst` -> `destination` copy(src: "/some/path", dst: "/another/path"); } ----- new_user.d ------ void main() { // works with no deprecation messages copy(source: "/some/path", destination: "/another/path"); } ----- conservative_user.d ------ void main() { // works without ambiguity error copy("/some/path", "/another/path"); } Since parameter names are not going to be part of the name managing, I propose that the compiler merges function declarations that produce the same mangled name in order to not emit ambiguity errors.
BTW, the following compiles today: --- library.d void copy(string source, string destination) { } deprecated("Parameters renamed: `src` -> `source` | `dst` -> `destination`") void copy(string src, string dst); deprecated("`distinasion` was renamed to `destination` to correct typos") void copy(string source, string distinasion); The problem is when you try to call the copy function: --- main.d import library; void main() { copy("/some/path", "/another/path"); // Error [1] } [1]: /sandbox/main.d(5): Error: `library.copy` called with argument types `(string, string)` matches both: /sandbox/library.d(1): `library.copy(string source, string destination)` and: /sandbox/library.d(7): `library.copy(string source, string distinasion)`
May 14
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Thursday, 14 May 2020 at 12:03:13 UTC, Petar Kirov 
[ZombineDev] wrote:
 [snip]

 [1]:
 /sandbox/main.d(5): Error: `library.copy` called with argument 
 types `(string, string)` matches both:
 /sandbox/library.d(1):     `library.copy(string source, string 
 destination)`
 and:
 /sandbox/library.d(7):     `library.copy(string source, string 
 distinasion)`
Interesting that it only mentions two of them and not all of them. If you comment one of them out, then it mentions the other. To your suggestion above, it's unclear if you are suggesting that the compiler read the deprecation message and change behavior somehow based on it. There is nothing stopping you from providing detailed deprecation messages today. Expanding on Seb's example, you could have something like below. void foo(int x, int y) { ... } deprecated("Parameters renamed: `xVal` -> `x` | `yVal` -> `y`") extern(D, argNames) void foo(int xVal, int yVal) { ... } The extern(D, argNames) is from Seb and is what would tell the compiler to only allow calling foo with keyword arguments. Thinking on it, you could make this even more general and have extern(D, positionOnly) extern(D, keywordOnly) which would force either positionOnly or keywordOnly syntax. That would resolve any concerns that I have.
May 14
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/14/20 9:20 AM, jmh530 wrote:
 On Thursday, 14 May 2020 at 12:03:13 UTC, Petar Kirov [ZombineDev] wrote:
 [snip]

 [1]:
 /sandbox/main.d(5): Error: `library.copy` called with argument types 
 `(string, string)` matches both:
 /sandbox/library.d(1):     `library.copy(string source, string 
 destination)`
 and:
 /sandbox/library.d(7):     `library.copy(string source, string 
 distinasion)`
Interesting that it only mentions two of them and not all of them. If you comment one of them out, then it mentions the other. To your suggestion above, it's unclear if you are suggesting that the compiler read the deprecation message and change behavior somehow based on it. There is nothing stopping you from providing detailed deprecation messages today. Expanding on Seb's example, you could have something like below. void foo(int x, int y) { ... } deprecated("Parameters renamed: `xVal` -> `x` | `yVal` -> `y`") extern(D, argNames) void foo(int xVal, int yVal) { ... } The extern(D, argNames) is from Seb and is what would tell the compiler to only allow calling foo with keyword arguments. Thinking on it, you could make this even more general and have extern(D, positionOnly) extern(D, keywordOnly) which would force either positionOnly or keywordOnly syntax. That would resolve any concerns that I have.
I don't think the extern(D, argNames) idea works. Both foos are mangled exactly the same, so you would have identical symbols in the object file. However, one COULD provide a prototype simply for renaming parameters (without implementation). I don't think you even need a specialized extern(D, argNames) marking, if the compiler will just prefer non-deprecated matches over deprecated ones. -Steve
May 14
parent reply Seb <seb wilzba.ch> writes:
On Thursday, 14 May 2020 at 13:33:30 UTC, Steven Schveighoffer 
wrote:
 On 5/14/20 9:20 AM, jmh530 wrote:
 On Thursday, 14 May 2020 at 12:03:13 UTC, Petar Kirov 
 [ZombineDev] wrote:
 [snip]

 [1]:
 /sandbox/main.d(5): Error: `library.copy` called with 
 argument types `(string, string)` matches both:
 /sandbox/library.d(1):     `library.copy(string source, 
 string destination)`
 and:
 /sandbox/library.d(7):     `library.copy(string source, 
 string distinasion)`
Interesting that it only mentions two of them and not all of them. If you comment one of them out, then it mentions the other. To your suggestion above, it's unclear if you are suggesting that the compiler read the deprecation message and change behavior somehow based on it. There is nothing stopping you from providing detailed deprecation messages today. Expanding on Seb's example, you could have something like below. void foo(int x, int y) { ... } deprecated("Parameters renamed: `xVal` -> `x` | `yVal` -> `y`") extern(D, argNames) void foo(int xVal, int yVal) { ... } The extern(D, argNames) is from Seb and is what would tell the compiler to only allow calling foo with keyword arguments. Thinking on it, you could make this even more general and have extern(D, positionOnly) extern(D, keywordOnly) which would force either positionOnly or keywordOnly syntax. That would resolve any concerns that I have.
I don't think the extern(D, argNames) idea works. Both foos are mangled exactly the same, so you would have identical symbols in the object file.
The entire point of extern(D, argNames) is that the argument names are now included in the mangling. It would be analogous to how the other extern declaration affect mangling (e.g. extern(C) will remove all arguments + types).
 However, one COULD provide a prototype simply for renaming 
 parameters (without implementation). I don't think you even 
 need a specialized extern(D, argNames) marking, if the compiler 
 will just prefer non-deprecated matches over deprecated ones.
Yeah, I that would work. Though the advantage of being able to write a custom body is that now you have a lot more freedom in case the new method differs from the old one by more than argument changes (e.g. semantic or ordering changes): --- add(int x_s, int y_s) { ... } deprecated extern(D, "argNames") add(int x_ms, int y_ms) { add(x_ms * 1000, y_ms * 1000); } --- Also note that if this would be allowed in the general case the following could work: --- extern(D, argNames): int sleep(int msecs) { ... } int sleep(int secs) { sleep(secs*1000); } sleep(msecs: 200); // OK sleep(secs: 100); // OK sleep(1); // ERROR --- --- extern(D, argNames): double sin(double rad) { ... } double sin(double deg) { } sin(rad: 0.5); // OK sin(deg: 90); // OK sin(0); // ERROR --- The compiler would need to trigger an ambiguity error if called without named arguments. Anyhow, I'm not interested in this general case. I just think that it could be a way to make deprecation work nicely.
May 14
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/14/20 12:18 PM, Seb wrote:
 On Thursday, 14 May 2020 at 13:33:30 UTC, Steven Schveighoffer wrote:
 However, one COULD provide a prototype simply for renaming parameters 
 (without implementation). I don't think you even need a specialized 
 extern(D, argNames) marking, if the compiler will just prefer 
 non-deprecated matches over deprecated ones.
Yeah, I that would work. Though the advantage of being able to write a custom body is that now you have a lot more freedom in case the new method differs from the old one by more than argument changes (e.g. semantic or ordering changes): --- add(int x_s, int y_s) { ... } deprecated extern(D, "argNames") add(int x_ms, int y_ms) { add(x_ms * 1000, y_ms * 1000); } ---
I don't think this works, because the parameter names are optional. In other words, add(1, 2) is going to silently do something else, which defeats the purpose of the deprecation. A deprecation of semantic meaning or position needs to be handled via a different function name (like it is today). Which means a deprecated prototype is all that is needed in the case of changing parameter names. -Steve
May 14
parent Seb <seb wilzba.ch> writes:
On Thursday, 14 May 2020 at 16:59:38 UTC, Steven Schveighoffer 
wrote:
 On 5/14/20 12:18 PM, Seb wrote:
 On Thursday, 14 May 2020 at 13:33:30 UTC, Steven Schveighoffer 
 wrote:
 [...]
Yeah, I that would work. Though the advantage of being able to write a custom body is that now you have a lot more freedom in case the new method differs from the old one by more than argument changes (e.g. semantic or ordering changes): --- add(int x_s, int y_s) { ... } deprecated extern(D, "argNames") add(int x_ms, int y_ms) { add(x_ms * 1000, y_ms * 1000); } ---
I don't think this works, because the parameter names are optional. In other words, add(1, 2) is going to silently do something else, which defeats the purpose of the deprecation.
Fair point. I guess this is another argument for providing library author with a mechanism to enforce "by argument name" only.
 A deprecation of semantic meaning or position needs to be 
 handled via a different function name (like it is today).

 Which means a deprecated prototype is all that is needed in the 
 case of changing parameter names.
Well, my point was that argument names have the potential for a lot more flexibility. Anyhow, I'm fine with a deprecated prototype/header as it would already be a lot better than the current status of this DIP (i.e. no options for deprecation).
May 14
prev sibling next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/14/20 1:19 AM, Walter Bright wrote:
 On 5/13/2020 12:31 PM, Steven Schveighoffer wrote:
 On 5/13/20 3:30 PM, Walter Bright wrote:
 In D, we do:
     void copy(string, string destination);
And how does the implementation of copy use that first parameter?
----- test.di ----- void copy(string, string destination); ----- test.d ------ void copy(string src, string destination) {     ... }
Not possible for templates. Also, an answer like "just use a .di file" is going to be a really hard pill to swallow. I think a mechanism to prevent one from using the name of a specific parameter for a call would be much more appreciated. Either parameters of a specific pattern, or make official the usage of implicit parameter names (i.e. _param_0) -Steve
May 14
prev sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, May 13, 2020 11:19:21 PM MDT Walter Bright via Digitalmars-d 
wrote:
 On 5/13/2020 12:31 PM, Steven Schveighoffer wrote:
 On 5/13/20 3:30 PM, Walter Bright wrote:
 In D, we do:
     void copy(string, string destination);
And how does the implementation of copy use that first parameter?
----- test.di ----- void copy(string, string destination); ----- test.d ------ void copy(string src, string destination) { ... }
In general, .di files are an antipattern that just causes problems. They're necessary in some cases, but they don't work at all with templates (and of course, a lot of idiomatic D code is templated) and are problematic with stuff like auto return types. I'd be tempted to start using .di files everywhere to prevent having to deal with anyone using named arguments with any library I wrote, but it would make the code extremely painful to maintain in comparison and simply wouldn't work for a lot of code. - Jonathan M Davis
May 15
prev sibling parent reply TheGag96 <thegag96 gmail.com> writes:
I totally think this DIP should go through, with no tedious 
opt-in impediments to anything. There is just no good reason to 
preemptively protect programmers at a language level from making 
a stylistic choice you don't like. If they want to use their 
named arguments in crazy ways (including reordering), just let 
them. People who find them helpful for certain situations can 
just use them distraction-free, and the people don't want to can 
just... not. The solution is incredibly clear.
May 14
next sibling parent Francesco Mecca <me francescomecca.eu> writes:
On Friday, 15 May 2020 at 00:12:36 UTC, TheGag96 wrote:
 I totally think this DIP should go through, with no tedious 
 opt-in impediments to anything. There is just no good reason to 
 preemptively protect programmers at a language level from 
 making a stylistic choice you don't like. If they want to use 
 their named arguments in crazy ways (including reordering), 
 just let them. People who find them helpful for certain 
 situations can just use them distraction-free, and the people 
 don't want to can just... not. The solution is incredibly clear.
I don't think the DIP should go through if there is no widespread consensus. D already has a mechanism for verbose function arguments that is sufficient in cases in which you want to be more explicit about parameters: https://dlang.org/phobos/std_typecons.html#.Flag
May 15
prev sibling parent WebFreak001 <d.forum webfreak.org> writes:
On Friday, 15 May 2020 at 00:12:36 UTC, TheGag96 wrote:
 I totally think this DIP should go through, with no tedious 
 opt-in impediments to anything. There is just no good reason to 
 preemptively protect programmers at a language level from 
 making a stylistic choice you don't like. If they want to use 
 their named arguments in crazy ways (including reordering), 
 just let them. People who find them helpful for certain 
 situations can just use them distraction-free, and the people 
 don't want to can just... not. The solution is incredibly clear.
I agree, I think how it is the DIP is in a good state where it is clearly opt-in by the caller. For not changing parameter names, there needs to be some document actually specifying what is a specifying what is a breaking change. The renaming of parameters is considered a breaking change for Microsoft products there but that doesn't mean every library dev follows that rule for their own stuff. Currently I think most D library devs already do stuff that could be considered even more breaking, because of traits and the whole ability to introspect. Named arguments are not so much of a problem because when a breaking change in names occurs, it's not a silent breakage but rather a compile time error for the caller. For the ABI and like having explicitly forced named arguments which are also mangled, I could really much see some future DIP allowing something like `void copy(string src:, string dst)` which would force you to at least call it with `copy(src: "", "")` - I really want this change but first this DIP should go through as it is right now, I think it's a good base for something like that.
May 15