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 Wednesday, 13 May 2020 at 19:55:20 UTC, Jonathan Marler wrote:
> [snip]
>>
>> Makes the documentation worse though.
>
> If it makes the documentation worse then it means the parameter names were helpful to the API, in which case you wouldn't do this.  The "copy" function isn't a good example because the "source" and "destination" parameter names are actually helpful to include.

I think the broader point though is that if the technique shouldn't be used on `copy` than it isn't a general solution for interacting with someone else's library.

What about an attribute? Perhaps @positionalOnly. It's ugly, but at least it's self-documenting. Using a named parameter with an @positionalOnly parameter would result in an error. This makes @positional opt-in and used rarely.
May 13, 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:
>
>> I found a way:
>> 
>> void copy(string, string destination)
>> {
>>      alias source = _param_0;
>> }
>> 
>> I didn't realize you could do this till now but this allows functions to "opt-out" of using named parameters.  We may want to consider using this pattern throughout phobos/druntime when we want want to prevent parameter names from being apart of the API.
>> 
>
> That is an implementation detail, and not a spec feature.
>
> It would have to be properly defined for it to be a sufficient workaround.
>

Darn

> Also, there is no guarantee that with this DIP:
>
> copy(_param_0: "foo", destination: "bar")
>
> doesn't work. There would have to be.
>

This one isn't as concerning to me.


May 13, 2020
On 5/13/2020 12:31 PM, Steven Schveighoffer wrote:
> On 5/13/20 3:30 PM, Walter Bright wrote:
>> In D, we do:
>>     void copy(string, string destination);
> And how does the implementation of copy use that first parameter?

----- test.di -----
void copy(string, string destination);

----- test.d ------
void copy(string src, string destination)
{
    ...
}


May 13, 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 14, 2020
On Thursday, 14 May 2020 at 05:19:21 UTC, Walter Bright wrote:
> On 5/13/2020 12:31 PM, Steven Schveighoffer wrote:
>> On 5/13/20 3:30 PM, Walter Bright wrote:
>>> In D, we do:
>>>     void copy(string, string destination);
>> And how does the implementation of copy use that first parameter?
>
> ----- test.di -----
> void copy(string, string destination);
>
> ----- test.d ------
> void copy(string src, string destination)
> {
>     ...
> }


Since .di files quite rare in D, compared to C and C++, can we also support the following:

----- test.d ------

// originally written as `void copy(string src, string dst)`:
void copy(string source, string destination)
{
    ...
}

// `copy` function author decided to improve the function signature,
// by not using abbreviated names. To prevent breaking changes they
// add a deprecated declaration:
deprecated("Parameters renamed: `src` -> `source` | `dst` -> `destination`")
void copy(string src, string dst);

// However the author made a mistake and actually wrote:
// void copy(string source, string distinasion)
// Being extra careful about their users, the author adds another
// deprecated declaration:
deprecate("`distinasion` was renamed to `destination` to correct typo")
void copy(string source, string distinasion);

----- old_time_user.d ------
void main()
{
    // keeps working, though emits a deprecation message:
    // Parameters renamed: `src` -> `source` | `dst` -> `destination`
    copy(src: "/some/path", dst: "/another/path");
}

----- new_user.d ------
void main()
{
    // works with no deprecation messages
    copy(source: "/some/path", destination: "/another/path");
}

----- conservative_user.d ------
void main()
{
    // works without ambiguity error
    copy("/some/path", "/another/path");
}


Since parameter names are not going to be part of the name managing, I propose that the compiler merges function declarations that produce the same mangled name in order to not emit ambiguity errors.
May 14, 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:
>> On 5/13/2020 12:31 PM, Steven Schveighoffer wrote:
>>> On 5/13/20 3:30 PM, Walter Bright wrote:
>>>> In D, we do:
>>>>     void copy(string, string destination);
>>> And how does the implementation of copy use that first parameter?
>>
>> ----- test.di -----
>> void copy(string, string destination);
>>
>> ----- test.d ------
>> void copy(string src, string destination)
>> {
>>     ...
>> }
>
>
> Since .di files quite rare in D, compared to C and C++, can we also support the following:
>
> ----- test.d ------
>
> // originally written as `void copy(string src, string dst)`:
> void copy(string source, string destination)
> {
>     ...
> }
>
> // `copy` function author decided to improve the function signature,
> // by not using abbreviated names. To prevent breaking changes they
> // add a deprecated declaration:
> deprecated("Parameters renamed: `src` -> `source` | `dst` -> `destination`")
> void copy(string src, string dst);
>
> // However the author made a mistake and actually wrote:
> // void copy(string source, string distinasion)
> // Being extra careful about their users, the author adds another
> // deprecated declaration:
> deprecate("`distinasion` was renamed to `destination` to correct typo")
> void copy(string source, string distinasion);
>
> ----- old_time_user.d ------
> void main()
> {
>     // keeps working, though emits a deprecation message:
>     // Parameters renamed: `src` -> `source` | `dst` -> `destination`
>     copy(src: "/some/path", dst: "/another/path");
> }
>
> ----- new_user.d ------
> void main()
> {
>     // works with no deprecation messages
>     copy(source: "/some/path", destination: "/another/path");
> }
>
> ----- conservative_user.d ------
> void main()
> {
>     // works without ambiguity error
>     copy("/some/path", "/another/path");
> }
>
>
> Since parameter names are not going to be part of the name managing, I propose that the compiler merges function declarations that produce the same mangled name in order to not emit ambiguity errors.

BTW, the following compiles today:

--- library.d
void copy(string source, string destination) { }

deprecated("Parameters renamed: `src` -> `source` | `dst` -> `destination`")
void copy(string src, string dst);

deprecated("`distinasion` was renamed to `destination` to correct typos")
void copy(string source, string distinasion);

The problem is when you try to call the copy function:

--- main.d
import library;
void main()
{
    copy("/some/path", "/another/path"); // Error [1]
}

[1]:
/sandbox/main.d(5): Error: `library.copy` called with argument types `(string, string)` matches both:
/sandbox/library.d(1):     `library.copy(string source, string destination)`
and:
/sandbox/library.d(7):     `library.copy(string source, string distinasion)`
May 14, 2020
On 5/14/20 1:19 AM, Walter Bright wrote:
> On 5/13/2020 12:31 PM, Steven Schveighoffer wrote:
>> On 5/13/20 3:30 PM, Walter Bright wrote:
>>> In D, we do:
>>>     void copy(string, string destination);
>> And how does the implementation of copy use that first parameter?
> 
> ----- test.di -----
> void copy(string, string destination);
> 
> ----- test.d ------
> void copy(string src, string destination)
> {
>      ...
> }

Not possible for templates.

Also, an answer like "just use a .di file" is going to be a really hard pill to swallow.

I think a mechanism to prevent one from using the name of a specific parameter for a call would be much more appreciated. Either parameters of a specific pattern, or make official the usage of implicit parameter names (i.e. _param_0)

-Steve
May 14, 2020
On 5/14/20 1:57 AM, Walter Bright wrote:
> On 5/13/2020 7:00 AM, Steven Schveighoffer wrote:
>> As was pointed out in the last review -- if you have structs with public member fields and you changed those names, the breakage would be more severe than just a broken initializer call:
>>
>> auto s = S(1, 2, 3);
>>
>> writeln(s.foo); // Error, no member foo, did you mean Foo?
> 
> I don't know about "more severe". It would just give an error that a matching function was not found, and would pretty-print the list of candidate functions.

I guess I should have said "more common". The point is, if you change the field names, people will notice first that they can't use the field names, not that the initializer call doesn't work.

I personally like named parameters, and I'm good with the struct initializer syntax as well. I just don't think that your assertion that the lack of complaints about initializer syntax breakage when people change field names is somehow proof that it won't be a problem for parameter name changes when named parameters are available. They would first complain that their usage of the structs has now broken.

At the same time, I'm fine with the result that changing parameter names is going to break calling code. Just name your parameters better.

My still only 2 complaints here are that there is a lack of deprecation path for parameter name changes, and that you cannot create wrapper types that forward the namedness.

> Besides, if you really don't want your users to use the parameter names,
> 
>      int foo(int _dkfjjiufheuehgthu, long _yer_mother_was_a_hamster, double _I_did_not_read_the_documentation);
> 
> and I bet they'll get the message.

I don't think they will. I think you would get at least one bug report per week that you should rename these parameters to something more intuitive.

-Steve