digitalmars.D - Discussion Thread: DIP 1030--Named Arguments--Final Review
- Mike Parker (21/21) May 11 2020 This is the discussion thread for the Final Review of DIP 1030,
- Mike Parker (3/8) May 11 2020 The Feedback Thread is here:
- Steven Schveighoffer (45/45) May 11 2020 The biggest problem I had with this DIP still remains -- You cannot
- Walter Bright (3/5) May 11 2020 I see this as something you can propose as another DIP to enhance DIP103...
- Gregory (19/24) May 12 2020 It's a feature that would be lost, I don't think named arguments
- Paulo Pinto (3/29) May 12 2020 That is no longer the case as of C# 8, the rules have been made
- Gregory (4/36) May 12 2020 Link? It was relaxed in C# 7.2 but I don't see anything for C# 8
- Paulo Pinto (3/12) May 12 2020 You're right I was mixing that with now being able to change the
- Paul Backus (11/25) May 12 2020 The logic behind this feature is that the rules it uses for
- Walter Bright (9/19) May 12 2020 Thank you for the clear explanation.
- Jonathan Marler (42/64) May 11 2020 I'd really like to see the DIP include a proposal on parameter
- Jacob Carlborg (43/72) May 13 2020 Yes, I agree.
- Dmitry Olshansky (7/17) May 13 2020 [snip]
- Steven Schveighoffer (32/84) May 13 2020 I love the Duration factory functions, one of the best parts of D.
- Paul Backus (9/22) May 13 2020 Even with such unambiguous abbreviations, the programmer still
- Steven Schveighoffer (12/33) May 13 2020 If it's always abbreviated (in a certain project, for instance), then
- Jonathan Marler (16/48) May 13 2020 Yes I also agree that what we have in phobos is already better
- Steven Schveighoffer (11/16) May 14 2020 Another convention could be -- if a parameter starts with underscore,
- Paul Backus (5/12) May 14 2020 +1
- Jonathan Marler (5/23) May 14 2020 Yeah even if it's not enforced, a convention like that would be
- Tove (28/33) May 14 2020 Some people love Named Arguments. (They might overuse it)
- jmh530 (34/35) May 12 2020 I think the arguments brought on in the previous review with
- 12345swordy (8/22) May 12 2020 If the user uses named arguments then that is by definition
- bachmeier (7/13) May 12 2020 I wasn't going to comment on this, but...yes, it makes perfect
- 12345swordy (18/25) May 12 2020 No, it does not make sense for the developer to opt in as the opt
- jmh530 (16/24) May 12 2020 The underlying worry is that the developer changes the names of
- Walter Bright (10/10) May 12 2020 We already have named arguments in D since the very beginning - the stru...
- Oraby (9/21) May 12 2020 How about providing a migration path by adding the ability to
- jmh530 (27/39) May 12 2020 I personally do not use this feature very much. I would expect
- jmh530 (5/9) May 12 2020 Actually it may compile based on what it says about "function
- Dmitry Olshansky (2/12) May 13 2020
- Steven Schveighoffer (12/27) May 13 2020 As was pointed out in the last review -- if you have structs with public...
- Walter Bright (7/14) May 13 2020 I don't know about "more severe". It would just give an error that a mat...
- Steven Schveighoffer (19/37) May 14 2020 I guess I should have said "more common". The point is, if you change
- Arvine (5/11) May 14 2020 I can't tell if this is a joke or not.
- Panke (8/21) May 14 2020 Personally and with regard to my experience with python I don't
- Timon Gehr (2/9) May 17 2020 Or you can just use `int foo(int, long, double);`.
- Arine (4/15) May 18 2020 Not that useful for open source code (the majority of D). Don't
- Timon Gehr (4/18) May 18 2020 int foo(int, long, double){
- Arine (4/25) May 18 2020 And that's better for readability? Both methods are equally as
- Timon Gehr (7/33) May 19 2020 I am not sure what your point is. Are you trying to argue that the
- Timon Gehr (3/40) May 19 2020 Actually, even if that is your point, I don't think we will reach an
- Arine (4/40) May 19 2020 Both are equally as bad in terms of readability. One is worse
- 12345swordy (4/28) May 19 2020 So if the implementation detail is standardized, would you still
- Arine (10/39) May 20 2020 Both methods are terrible. A pull request that used either method
- 12345swordy (8/51) May 20 2020 void fun(int,int)
- Arine (18/70) May 21 2020 Editors that use the signature to get parameter names to help
- Paul Backus (23/39) May 20 2020 Here's a method that works using existing language features and
- Paul Backus (15/19) May 21 2020 To wit:
- Jonathan M Davis (33/43) May 15 2020 I have _never_ used the struct initialization syntax, and I'm not sure t...
- Walter Bright (9/23) May 16 2020 I almost never change a parameter name. I also can't see myself using na...
- Jonathan M Davis (8/11) May 16 2020 Marginally. Personally, I've always been of the opinion that just using ...
- Walter Bright (2/7) May 16 2020 Glad to see we can agree on something!
- Jacob Carlborg (45/49) May 17 2020 I guess it depends on what kind of code you write. It's super useful
- Arine (23/35) May 15 2020 There's a simple workaround; it can even be deprecated!
- matheus (10/18) May 16 2020 That's true.
- Paolo Invernizzi (6/25) May 17 2020 Happened sometimes in Phobos, to put the range as a first
- 12345swordy (5/8) May 16 2020 You can make the same remark when it comes to changing parameter
- jmh530 (23/33) May 14 2020 Given the recent discussions, I am reconsidering what I said
- Andrej Mitrovic (11/14) May 12 2020 I see people mentioning wrapper overloads to enable deprecation
- jmh530 (15/27) May 13 2020 So there wouldn't be a warning if they call foo(10, 20)?
- Seb (17/33) May 13 2020 What happens if
- jmh530 (2/9) May 13 2020 Even better!
- Jacob Carlborg (13/17) May 13 2020 Regarding renaming parameters will break the API. Swift supports giving
- Paul Backus (11/22) May 13 2020 Worth noting that this can also be done in D using local alias
- Steven Schveighoffer (20/49) May 13 2020 Note that in Swift, _ means "unnamed parameter", it's not an actual
- Luhrel (17/29) May 22 2020 What about a @required (or a better name) that will force the
- Walter Bright (3/13) May 13 2020 In D, we do:
- Steven Schveighoffer (3/19) May 13 2020 And how does the implementation of copy use that first parameter?
- Jonathan Marler (11/31) May 13 2020 I found a way:
- Panke (2/12) May 13 2020 Makes the documentation worse though.
- Jonathan Marler (6/21) May 13 2020 If it makes the documentation worse then it means the parameter
- jmh530 (8/16) May 13 2020 I think the broader point though is that if the technique
- Jonathan M Davis (19/44) May 15 2020 Just because having the parameter names in the documentation helps make ...
- Jonathan Marler (6/40) May 13 2020 I've created a PR to use this pattern in some of the functions in
- Steven Schveighoffer (7/19) May 13 2020 That is an implementation detail, and not a spec feature.
- Jonathan Marler (4/24) May 13 2020 Darn
- Walter Bright (8/12) May 13 2020 ----- test.di -----
- Petar Kirov [ZombineDev] (48/61) May 14 2020 Since .di files quite rare in D, compared to C and C++, can we
- Petar Kirov [ZombineDev] (26/90) May 14 2020 BTW, the following compiles today:
- jmh530 (20/29) May 14 2020 Interesting that it only mentions two of them and not all of
- Steven Schveighoffer (8/43) May 14 2020 I don't think the extern(D, argNames) idea works. Both foos are mangled
- Seb (39/84) May 14 2020 The entire point of extern(D, argNames) is that the argument
- Steven Schveighoffer (9/25) May 14 2020 I don't think this works, because the parameter names are optional.
- Seb (10/34) May 14 2020 Fair point.
- Steven Schveighoffer (9/23) May 14 2020 Not possible for templates.
- Jonathan M Davis (10/23) May 15 2020 In general, .di files are an antipattern that just causes problems. They...
- TheGag96 (8/8) May 14 2020 I totally think this DIP should go through, with no tedious
- Francesco Mecca (7/15) May 15 2020 I don't think the DIP should go through if there is no widespread
- WebFreak001 (21/29) May 15 2020 I agree, I think how it is the DIP is in a good state where it is
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 2020
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 2020
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 2020
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 2020
On Tuesday, 12 May 2020 at 05:36:11 UTC, Walter Bright wrote:On 5/11/2020 5:48 AM, Steven Schveighoffer wrote: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.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 12 2020
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:more flexible.On 5/11/2020 5:48 AM, Steven Schveighoffer wrote: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.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 12 2020
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:that relaxes them further. But it didn't change the requirement for defaults or positioning.On Tuesday, 12 May 2020 at 05:36:11 UTC, Walter Bright wrote:more flexible.On 5/11/2020 5:48 AM, Steven Schveighoffer wrote: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.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 12 2020
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:You're right I was mixing that with now being able to change the order of named arguments.On Tuesday, 12 May 2020 at 12:11:11 UTC, Gregory wrote:8 that relaxes them further. But it didn't change the requirement for defaults or positioning.[...]made more flexible.
May 12 2020
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 2020
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_initThank 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 2020
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 2020
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 helpfulYes, I agree.A sleep function that takes milliseconds on the other hand could be helpful: sleep(100); sleep(msecs:100); // helpfulI 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 secsSame 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 2020
On Wednesday, 13 May 2020 at 08:17:26 UTC, Jacob Carlborg wrote:On 2020-05-12 08:22, Jonathan Marler wrote:[snip] Exactly my thoughts, well put Jacob![...]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:Again, pure gold and spot on. — Dmitry Olshansky Stay safe and have fun![...]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]
May 13 2020
On 5/13/20 4:17 AM, Jacob Carlborg wrote:On 2020-05-12 08:22, Jonathan Marler wrote: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.A sleep function that takes milliseconds on the other hand could be helpful: sleep(100); sleep(msecs:100); // helpfulI 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 tooI 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.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();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 2020
On Wednesday, 13 May 2020 at 12:15:38 UTC, Steven Schveighoffer wrote:On 5/13/20 4:17 AM, Jacob Carlborg wrote: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.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.
May 13 2020
On 5/13/20 9:34 AM, Paul Backus wrote:On Wednesday, 13 May 2020 at 12:15:38 UTC, Steven Schveighoffer wrote: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. -SteveOn 5/13/20 4:17 AM, Jacob Carlborg wrote: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.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.
May 13 2020
On Wednesday, 13 May 2020 at 08:17:26 UTC, Jacob Carlborg wrote:On 2020-05-12 08:22, Jonathan Marler wrote: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.A sleep function that takes milliseconds on the other hand could be helpful: sleep(100); sleep(msecs:100); // helpfulI 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:Good point, if we defer to the first rule, there may be no need to have a convention for generic parameters like these.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: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);msecs secsSame 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.Yeah these are the types of things I think we should discuss, especially for the standard library before we enable this feature.
May 13 2020
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 2020
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 2020
On Thursday, 14 May 2020 at 19:55:02 UTC, Steven Schveighoffer wrote:On 5/12/20 2:22 AM, Jonathan Marler wrote: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 :)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 2020
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. -SteveSome 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 2020
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 2020
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: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[...]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. [...]
May 12 2020
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 2020
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 2020
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. -AlexThe 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 2020
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 2020
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 2020
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 2020
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 2020
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 2020
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 2020
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 2020
On 5/14/20 1:57 AM, Walter Bright wrote:On 5/13/2020 7:00 AM, Steven Schveighoffer wrote: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.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.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 2020
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 2020
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: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.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 2020
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 2020
On Sunday, 17 May 2020 at 13:25:35 UTC, Timon Gehr wrote:On 14.05.20 07:57, Walter Bright wrote: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.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 18 2020
On 19.05.20 02:05, Arine wrote:On Sunday, 17 May 2020 at 13:25:35 UTC, Timon Gehr wrote:int foo(int, long, double){ return cast(int)(_param_0+_param_1+_param_2); }On 14.05.20 07:57, Walter Bright wrote: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.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 18 2020
On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote:On 19.05.20 02:05, Arine wrote:And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".On Sunday, 17 May 2020 at 13:25:35 UTC, Timon Gehr wrote:int foo(int, long, double){ return cast(int)(_param_0+_param_1+_param_2); }On 14.05.20 07:57, Walter Bright wrote: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.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 18 2020
On 19.05.20 04:35, Arine wrote:On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote: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.On 19.05.20 02:05, Arine wrote:And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".On Sunday, 17 May 2020 at 13:25:35 UTC, Timon Gehr wrote:int foo(int, long, double){ return cast(int)(_param_0+_param_1+_param_2); }On 14.05.20 07:57, Walter Bright wrote: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.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 19 2020
On 19.05.20 10:01, Timon Gehr wrote:On 19.05.20 04:35, Arine wrote:Actually, even if that is your point, I don't think we will reach an agreement, nor would it be important to do so.On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote: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.On 19.05.20 02:05, Arine wrote:And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".On Sunday, 17 May 2020 at 13:25:35 UTC, Timon Gehr wrote:int foo(int, long, double){ return cast(int)(_param_0+_param_1+_param_2); }On 14.05.20 07:57, Walter Bright wrote: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.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 19 2020
On Tuesday, 19 May 2020 at 08:01:09 UTC, Timon Gehr wrote:On 19.05.20 04:35, Arine wrote:Both are equally as bad in terms of readability. One is worse because it uses an implementation detail that can change at any time.On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote: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.On 19.05.20 02:05, Arine wrote:And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".On Sunday, 17 May 2020 at 13:25:35 UTC, Timon Gehr wrote:int foo(int, long, double){ return cast(int)(_param_0+_param_1+_param_2); }On 14.05.20 07:57, Walter Bright wrote: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.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 19 2020
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:So if the implementation detail is standardized, would you still object to this? -AlexOn 19.05.20 04:35, Arine wrote:Both are equally as bad in terms of readability. One is worse because it uses an implementation detail that can change at any time.On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote: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.[...]And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".
May 19 2020
On Wednesday, 20 May 2020 at 03:04:13 UTC, 12345swordy wrote:On Wednesday, 20 May 2020 at 02:09:27 UTC, Arine wrote: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.On Tuesday, 19 May 2020 at 08:01:09 UTC, Timon Gehr wrote:So if the implementation detail is standardized, would you still object to this? -AlexOn 19.05.20 04:35, Arine wrote:Both are equally as bad in terms of readability. One is worse because it uses an implementation detail that can change at any time.On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote: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.[...]And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".
May 20 2020
On Wednesday, 20 May 2020 at 20:01:51 UTC, Arine wrote:On Wednesday, 20 May 2020 at 03:04:13 UTC, 12345swordy wrote: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. -AlexOn Wednesday, 20 May 2020 at 02:09:27 UTC, Arine wrote: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.On Tuesday, 19 May 2020 at 08:01:09 UTC, Timon Gehr wrote:So if the implementation detail is standardized, would you still object to this? -AlexOn 19.05.20 04:35, Arine wrote:Both are equally as bad in terms of readability. One is worse because it uses an implementation detail that can change at any time.On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote: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.[...]And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".
May 20 2020
On Thursday, 21 May 2020 at 00:35:21 UTC, 12345swordy wrote:On Wednesday, 20 May 2020 at 20:01:51 UTC, Arine wrote: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.On Wednesday, 20 May 2020 at 03:04:13 UTC, 12345swordy wrote: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. -AlexOn Wednesday, 20 May 2020 at 02:09:27 UTC, Arine wrote: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.On Tuesday, 19 May 2020 at 08:01:09 UTC, Timon Gehr wrote:So if the implementation detail is standardized, would you still object to this? -AlexOn 19.05.20 04:35, Arine wrote:Both are equally as bad in terms of readability. One is worse because it uses an implementation detail that can change at any time.On Tuesday, 19 May 2020 at 01:07:38 UTC, Timon Gehr wrote: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.[...]And that's better for readability? Both methods are equally as bad. That one may be worse because it is an undocumented "feature".
May 21 2020
On Wednesday, 20 May 2020 at 20:01:51 UTC, Arine wrote:On Wednesday, 20 May 2020 at 03:04:13 UTC, 12345swordy wrote: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.So if the implementation detail is standardized, would you still object to this? -AlexBoth 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 2020
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 2020
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 2020
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#FlagGiven 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 2020
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#YesMarginally. 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 2020
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 2020
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 membersI 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 2020
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 2020
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:...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.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.
May 16 2020
On Saturday, 16 May 2020 at 13:30:34 UTC, matheus wrote:On Friday, 15 May 2020 at 23:45:46 UTC, Arine wrote: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...On Wednesday, 13 May 2020 at 00:37:51 UTC, Walter Bright wrote:...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.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.
May 17 2020
On Friday, 15 May 2020 at 23:45:46 UTC, Arine wrote: Really ifan 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 2020
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: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.[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]
May 14 2020
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.mdI 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 2020
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 2020
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: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).This is the discussion thread for the Final Review of DIP 1030, "Named Arguments": https://github.com/dlang/DIPs/blob/7d114c93edb02d8fc4b05f0716bdb6057905fec2/DIPs/DIP1030.mdI 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 13 2020
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 2020
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.mdRegarding 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 2020
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 2020
On 5/13/20 9:15 AM, Paul Backus wrote:On Wednesday, 13 May 2020 at 07:55:33 UTC, Jacob Carlborg wrote: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. -SteveRegarding 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 2020
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. -SteveWhat 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 2020
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 2020
On 5/13/20 3:30 PM, Walter Bright wrote:On 5/13/2020 12:55 AM, Jacob Carlborg wrote:And how does the implementation of copy use that first parameter? -SteveRegarding 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 2020
On Wednesday, 13 May 2020 at 19:31:24 UTC, Steven Schveighoffer wrote:On 5/13/20 3:30 PM, Walter Bright 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.On 5/13/2020 12:55 AM, Jacob Carlborg wrote:And how does the implementation of copy use that first parameter? -SteveRegarding 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 2020
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 2020
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: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 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 2020
On Wednesday, 13 May 2020 at 19:55:20 UTC, Jonathan Marler wrote:[snip]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.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 2020
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: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 DavisOn Wednesday, 13 May 2020 at 19:44:32 UTC, Jonathan Marler wrote: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 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 15 2020
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: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.On 5/13/20 3:30 PM, Walter Bright 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.On 5/13/2020 12:55 AM, Jacob Carlborg wrote:And how does the implementation of copy use that first parameter? -SteveRegarding 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 2020
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 2020
On Wednesday, 13 May 2020 at 20:42:32 UTC, Steven Schveighoffer wrote:On 5/13/20 3:44 PM, Jonathan Marler wrote:DarnI 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.This one isn't as concerning to me.
May 13 2020
On 5/13/2020 12:31 PM, Steven Schveighoffer wrote:On 5/13/20 3:30 PM, Walter Bright wrote:----- test.di ----- void copy(string, string destination); ----- test.d ------ void copy(string src, string destination) { ... }In D, we do: void copy(string, string destination);And how does the implementation of copy use that first parameter?
May 13 2020
On Thursday, 14 May 2020 at 05:19:21 UTC, Walter Bright wrote:On 5/13/2020 12:31 PM, Steven Schveighoffer wrote: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.On 5/13/20 3:30 PM, Walter Bright wrote:----- test.di ----- void copy(string, string destination); ----- test.d ------ void copy(string src, string destination) { ... }In D, we do: void copy(string, string destination);And how does the implementation of copy use that first parameter?
May 14 2020
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: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)`On 5/13/2020 12:31 PM, Steven Schveighoffer wrote: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.On 5/13/20 3:30 PM, Walter Bright wrote:----- test.di ----- void copy(string, string destination); ----- test.d ------ void copy(string src, string destination) { ... }In D, we do: void copy(string, string destination);And how does the implementation of copy use that first parameter?
May 14 2020
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 2020
On 5/14/20 9:20 AM, jmh530 wrote:On Thursday, 14 May 2020 at 12:03:13 UTC, Petar Kirov [ZombineDev] wrote: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[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 2020
On Thursday, 14 May 2020 at 13:33:30 UTC, Steven Schveighoffer wrote:On 5/14/20 9:20 AM, jmh530 wrote: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).On Thursday, 14 May 2020 at 12:03:13 UTC, Petar Kirov [ZombineDev] wrote: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.[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.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 2020
On 5/14/20 12:18 PM, Seb wrote:On Thursday, 14 May 2020 at 13:33:30 UTC, Steven Schveighoffer wrote: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. -SteveHowever, 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); } ---
May 14 2020
On Thursday, 14 May 2020 at 16:59:38 UTC, Steven Schveighoffer wrote:On 5/14/20 12:18 PM, Seb wrote:Fair point. I guess this is another argument for providing library author with a mechanism to enforce "by argument name" only.On Thursday, 14 May 2020 at 13:33:30 UTC, Steven Schveighoffer wrote: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.[...]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); } ---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 2020
On 5/14/20 1:19 AM, Walter Bright wrote:On 5/13/2020 12:31 PM, Steven Schveighoffer wrote: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) -SteveOn 5/13/20 3:30 PM, Walter Bright wrote:----- test.di ----- void copy(string, string destination); ----- test.d ------ void copy(string src, string destination) { ... }In D, we do: void copy(string, string destination);And how does the implementation of copy use that first parameter?
May 14 2020
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: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 DavisOn 5/13/20 3:30 PM, Walter Bright wrote:----- test.di ----- void copy(string, string destination); ----- test.d ------ void copy(string src, string destination) { ... }In D, we do: void copy(string, string destination);And how does the implementation of copy use that first parameter?
May 15 2020
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 2020
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 2020
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 2020