May 13, 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

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

Something like:

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

And then the compiler emits warnings if you use `foo(x_val : 10, y_val : 20)`.
May 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/7d114c93edb02d8fc4b05f0716bdb6057905fec2/DIPs/DIP1030.md 

Regarding renaming parameters will break the API. Swift supports giving a different name which are used locally:

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

Should be called like this:

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

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

This allows to rename a parameter (the local name) without breaking the API.

-- 
/Jacob Carlborg
May 13, 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 helpful

Yes, I agree.

> A sleep function that takes milliseconds on the other hand could be helpful:
> 
> sleep(100);
> sleep(msecs:100); // helpful

I disagree. It's much better what we already have. The `sleep` method on `Thread` takes a duration, instead of a specific time unit. The duration is also encoded in its own type:

Thread.getThis.sleep(100.msecs);
Thread.getThis.sleep(1.seconds); // this works too

I guess one could do this:

Thread.getThis.sleep(duration: 1.seconds);

Not sure if it would help though.

Instead of passing a random integer, we pass a type that encodes the meaning of the value. It's also more flexible, because you can create a Duration out of many different units.

> Given that, here are a list of conventions:
>
> 2. Common generic parameter names
> 
> p (generic pointer argument, prefer this over ptr or pointer)
> s (generic string argument, prefer this over str or string)
> i (generic integer argument)

I disagree. I think there are very few cases of APIs where a function expects a truly generic value. It's better to try to encode the purpose or how a value is used in the parameter name. Naming something based on what it is rarely useful, we have a much better system for that, which is the type system :). For example:

void foo(int* p);
void foo(int* pointer);
void foo(int* ptr);

The signature already contains the information that the parameter is a pointer, no need to encode that in the name, be it `pointer`, `ptr` or `p`. There are cases where a function accepts a truly generic value, like a function that can convert any value to a string:

string toString(T)(T value);
toString(value: 3);

But in this case named arguments don't help much and I think it falls under the first category (your example with `floor`). Better to call it like:

toString(3);
3.toString();

> msecs
> secs

Same thing as the `sleep` method. Should not be a plain int, should be its own type.

Also, we should avoiding having short, abbreviated symbol names (any kind of symbol names, not just parameter names). Although it's worse to have abbreviated names which are part of the API or show up in generated documentation. There are always exceptions, like when abbreviated name is more known and common than the actual full name. Examples are: HTTP, FTP and so on.

-- 
/Jacob Carlborg
May 13, 2020
On Wednesday, 13 May 2020 at 08:17:26 UTC, Jacob Carlborg wrote:
> On 2020-05-12 08:22, Jonathan Marler wrote:
>> [...]
>
> I disagree. It's much better what we already have. The `sleep` method on `Thread` takes a duration, instead of a specific time unit. The duration is also encoded in its own type:
[snip]
Exactly my thoughts, well put Jacob!

>> [...]
>
> I disagree. I think there are very few cases of APIs where a function expects a truly generic value. It's better to try to encode the purpose or how a value is used in the parameter name. [snip]

Again, pure gold and spot on.

—
Dmitry Olshansky
Stay safe and have fun!
May 13, 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/13/20 4:17 AM, Jacob Carlborg wrote:
> On 2020-05-12 08:22, Jonathan Marler wrote:

>> A sleep function that takes milliseconds on the other hand could be helpful:
>>
>> sleep(100);
>> sleep(msecs:100); // helpful
> 
> I disagree. It's much better what we already have. The `sleep` method on `Thread` takes a duration, instead of a specific time unit. The duration is also encoded in its own type:
> 
> Thread.getThis.sleep(100.msecs);
> Thread.getThis.sleep(1.seconds); // this works too

I love the Duration factory functions, one of the best parts of D.

Just wanted to point out here that sleep is a static function, so you only need to do Thread.sleep(1.seconds).

I also wanted to say that the example has to do with existing code, not specifically the way to sleep in D. The example is *if you have* a sleep function that takes milliseconds, as could be in a library other than druntime (like say an event library that needs to listen for other events for other fibers).

While it might be nice to adjust such a function to take a Duration, that would be a breaking change, and simply changing the name to reflect better the parameter would be a non-breaking first step.

>> Given that, here are a list of conventions:
>>
>> 2. Common generic parameter names
>>
>> p (generic pointer argument, prefer this over ptr or pointer)
>> s (generic string argument, prefer this over str or string)
>> i (generic integer argument)
> 
> I disagree. I think there are very few cases of APIs where a function expects a truly generic value. It's better to try to encode the purpose or how a value is used in the parameter name. Naming something based on what it is rarely useful, we have a much better system for that, which is the type system :). For example:
> 
> void foo(int* p);
> void foo(int* pointer);
> void foo(int* ptr);
> 
> The signature already contains the information that the parameter is a pointer, no need to encode that in the name, be it `pointer`, `ptr` or `p`.

I agree, but also there's a lack of convincing examples here. I would say for pointers or references where data is to be read, `src` is a good name, and `dest` is a good name for a pointer to data to be written.

e.g.:

copyTo(T)(ref T src, ref T dest);

Other than that, I can't really imagine that there's any hard rule that we need to adhere to -- pointers are passed for various reasons, you should identify the purpose with the name.

> There are cases where a function accepts a truly generic value, like a function that can convert any value to a string:
> 
> string toString(T)(T value);
> toString(value: 3);
> 
> But in this case named arguments don't help much and I think it falls under the first category (your example with `floor`). Better to call it like:
> 
> toString(3);
> 3.toString();

Agree.

> Also, we should avoiding having short, abbreviated symbol names (any kind of symbol names, not just parameter names). Although it's worse to have abbreviated names which are part of the API or show up in generated documentation. There are always exceptions, like when abbreviated name is more known and common than the actual full name. Examples are: HTTP, FTP and so on.

HTTP and FTP are acronyms, which in my opinion ARE the full names.

Abbreviations are fine when the abbreviation is unambiguous, like src and dest.

One thing that should be added: for overloaded functions, names of similar parameters should be the same.

Though I suppose one could select a specific overload for literals using naming? Is that something that should be promoted?

e.g.:

double atan(double doubleVal);
real atan(real realVal);

-Steve
May 13, 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 Wednesday, 13 May 2020 at 12:15:38 UTC, Steven Schveighoffer wrote:
> On 5/13/20 4:17 AM, Jacob Carlborg wrote:
>> On 2020-05-12 08:22, Jonathan Marler wrote:
>> Also, we should avoiding having short, abbreviated symbol names (any kind of symbol names, not just parameter names). Although it's worse to have abbreviated names which are part of the API or show up in generated documentation. There are always exceptions, like when abbreviated name is more known and common than the actual full name. Examples are: HTTP, FTP and so on.
>
> HTTP and FTP are acronyms, which in my opinion ARE the full names.
>
> Abbreviations are fine when the abbreviation is unambiguous, like src and dest.

Even with such unambiguous abbreviations, the programmer still has to keep track of (a) which words are abbreviated and which are spelled out ("is it `source` or `src`?"), and (b) which abbreviations are used for words with multiple possibilities (e.g., "is it `dest` or `dst`?"). Spelling everything out means you never have to think about this stuff at all--there's always exactly one obvious, correct choice.
May 13, 2020
On 5/13/20 9:34 AM, Paul Backus wrote:
> On Wednesday, 13 May 2020 at 12:15:38 UTC, Steven Schveighoffer wrote:
>> On 5/13/20 4:17 AM, Jacob Carlborg wrote:
>>> On 2020-05-12 08:22, Jonathan Marler wrote:
>>> Also, we should avoiding having short, abbreviated symbol names (any kind of symbol names, not just parameter names). Although it's worse to have abbreviated names which are part of the API or show up in generated documentation. There are always exceptions, like when abbreviated name is more known and common than the actual full name. Examples are: HTTP, FTP and so on.
>>
>> HTTP and FTP are acronyms, which in my opinion ARE the full names.
>>
>> Abbreviations are fine when the abbreviation is unambiguous, like src and dest.
> 
> Even with such unambiguous abbreviations, the programmer still has to keep track of (a) which words are abbreviated and which are spelled out ("is it `source` or `src`?"), and (b) which abbreviations are used for words with multiple possibilities (e.g., "is it `dest` or `dst`?"). Spelling everything out means you never have to think about this stuff at all--there's always exactly one obvious, correct choice.

If it's always abbreviated (in a certain project, for instance), then it's obvious, even as an abbreviation. What you shouldn't have is a project with functions that have `dest` and `dst`.

You are not going to ever get global consensus for every project on every name. What I was saying is, intra-project consistency is more important than forbidding abbreviations. Even when abbreviations are not allowed, you can have different spellings (is it `color` or `colour`?)

Naming conventions for parameters really should just look to naming conventions for functions for guidance I think. Many of the same rules apply.

-Steve
May 13, 2020
On 5/13/20 9:15 AM, Paul Backus wrote:
> On Wednesday, 13 May 2020 at 07:55:33 UTC, Jacob Carlborg wrote:
>> Regarding renaming parameters will break the API. Swift supports giving a different name which are used locally:
>>
>> func copy(_ source: String, to destination: String)
>>
>> Should be called like this:
>>
>> copy("foo", to: "bar")
>>
>> `_` indicates that the argument can not be named when calling the function. `to` is the name that is used when calling the function. `source` and `destination` are the names used locally in the implementation of the function.
>>
>> This allows to rename a parameter (the local name) without breaking the API.
> 
> Worth noting that this can also be done in D using local alias declarations:
> 
> void copy(const(char)[] _, char[] to) {
>      alias source = _;
>      alias destination = to;
>      // etc.
> }
> 
> Granted, the D compiler will not actually stop anyone from giving the first argument by name, but it's hard to imagine why anyone would want to.

Note that in Swift, _ means "unnamed parameter", it's not an actual name. So we can't really do what it can do:

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

could be called like:

copy("foo", "bar")

The equivalent in D would have multiple parameter names as _ which isn't allowed.

Hm... an interesting proposition, we could provide a way to disallow using names if the name starts with something like _:

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

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

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

-Steve