February 18, 2019
On Monday, 18 February 2019 at 08:32:02 UTC, RazvanN wrote:
> On Sunday, 17 February 2019 at 21:04:23 UTC, Yuxuan Shui wrote:
>> [...]
>
> How about this: simply adding the ability to name the argument when calling a function? Example:
>
> [...]

Now this is a solution that I can get behind.
February 18, 2019
On Monday, 18 February 2019 at 08:32:02 UTC, RazvanN wrote:
> On Sunday, 17 February 2019 at 21:04:23 UTC, Yuxuan Shui wrote:
>> [...]
>
> How about this: simply adding the ability to name the argument when calling a function? Example:
>
> void rectangle(int width, int height) {}
>
> void main()
> {
>     rectangle(1, 2);
>     rectangle(width: 1, height: 2);
>     rectangle(height: 2, width: 1);
>     rectangle(width: 1, 2);    // error
> }
>


1) What about typos/wrong names?

rectangle(width: 1, hight: 2)

2) How will this deal with parameter renames / deprecation?

If (1) isn't checked, introducing this later would break a lot of code.
February 18, 2019
On Monday, 18 February 2019 at 19:27:15 UTC, Seb wrote:
> On Monday, 18 February 2019 at 08:32:02 UTC, RazvanN wrote:
>> On Sunday, 17 February 2019 at 21:04:23 UTC, Yuxuan Shui wrote:
>>> [...]
>>
>> How about this: simply adding the ability to name the argument when calling a function? Example:
>>
>> void rectangle(int width, int height) {}
>>
>> void main()
>> {
>>     rectangle(1, 2);
>>     rectangle(width: 1, height: 2);
>>     rectangle(height: 2, width: 1);
>>     rectangle(width: 1, 2);    // error
>> }
>>
>
>
> 1) What about typos/wrong names?
>
> rectangle(width: 1, hight: 2)

Easy: you print the parameters that do not match: "Unknown parameter name". If a parameter name is not in the list of parameters, you print it.

>
> 2) How will this deal with parameter renames / deprecation?
>
The easiest solution would be to simply do nothing. Once a parameter name is changed, then it has to be updated on caller site. Later on we can add smarter stuff.

> If (1) isn't checked, introducing this later would break a lot of code.

Indeed.
February 18, 2019
On Saturday, 16 February 2019 at 23:56:45 UTC, Vladimir Panteleev wrote:
> @named is not the best idea.

I discourage @named, too.

The lesser evil is when implementors break call sites whenever implementors rename their arguments. It's rare that this happens purely for style. (If the renaming is caused by a semantic change in the function, then we want noisy breakage in the call sites anyway, with or without @named.)

Function designers are already annotating everything with @property const @safe pure nothrow @nogc. Let's not bloat the definition even more with @named.

Besides @named, I'm happy with the proposal. Expressiveness and automatic checks are good.

-- Simon
February 19, 2019
On Monday, 18 February 2019 at 13:18:15 UTC, Rubn wrote:
> On Monday, 18 February 2019 at 10:17:32 UTC, Atila Neves wrote:
>> On Friday, 15 February 2019 at 17:43:52 UTC, 12345swordy wrote:
>>> On Friday, 15 February 2019 at 17:38:23 UTC, Francesco Mecca wrote:
>>>> On Friday, 15 February 2019 at 13:49:04 UTC, Atila Neves wrote:
>>>>> [...]
>>>>
>>>> I think that the solution proposed by Atila is better for the following reasons:
>>>> 1. it is a library solution
>>>> 2. allows both the user and the author of a library to specify functions with named parameters
>>>> 3. it is very lightweight
>>>>
>>>> [...]
>>>
>>> You miss the other reason on why it is not enough: Compile time and run-time performance penalty.
>>> -Alex
>>
>> Run-time? I'd expect the call to inlined. It'll definitely take longer to compile though, but I'm at a loss why named parameters in the compiler are expected to be free.
>
> The compiler isn't some magic device, your implementation is not easily optimized out to have no runtime cost. Even LDC has trouble optimizing it, and forget about DMD.
>
> struct Foo {
>     int[1024] value;
> }

<snip>

Good shout, thanks for bringing that up. I fixed this in version 0.0.2 (just pushed), and now both `callSlowFoo` and `callFastFoo` below yield the exact same assembly with ldc, and the function calls were inlined:

----------------------------------------------
import kwargs;

struct Foo {
    int[1024] value;
}

void fastFoo(ref Foo faa) {
    import core.stdc.stdio: printf;
    foreach(int i, ref v; faa.value) {
        printf("%d ", v);
    }
    printf("\n");
 }

alias slowFoo = kwargify!fastFoo;


void callSlowFoo() {
    Foo foo;
    initFoo(foo);
    slowFoo(foo);
}

void callFastFoo() {
    Foo foo;
    initFoo(foo);
    fastFoo(foo);
}

void initFoo(ref Foo foo) {
    foreach(int i, ref v; foo.value) {
        v = i;
    }
}

void main() {
    callSlowFoo;
    // callFastFoo; // it's the same!
}

----------------------------------------------


February 26, 2019
On Friday, February 15, 2019 5:56:45 AM MST Mike Parker via Digitalmars-d wrote:
> This is the feedback thread for the first round of Community Review for DIP 1019, "Named Arguments Lite":
>
> https://github.com/dlang/DIPs/blob/23ef47a94e0fdd5ddc4b2f6b2f4dcfd3c1f43aa 6/DIPs/DIP1019.md
>
> All review-related feedback on and discussion of the DIP should occur in this thread. The review period will end at 11:59 PM ET on March 1, or when I make a post declaring it complete.
>
> At the end of Round 1, if further review is deemed necessary, the DIP will be scheduled for another round of Community Review. Otherwise, it will be queued for the Final Review and Formal Assessment by the language maintainers.
>
> Please familiarize yourself with the documentation for the Community Review before participating.
>
> https://github.com/dlang/DIPs/blob/master/PROCEDURE.md#community-review
>
> Thanks in advance to all who participate.

I honestly don't understand the whole deal about discussing "repurposing" function parameters. If you refactor a function, it needs to continue to work with all existing calls to it, or it's going to break code. So, stuff like swapping x and y and the like make absolutely no sense. If you're going to screw up existing function calls by changing the function's signature, then you can't change the function's signature. So, I don't see any point in even worrying about function parameters being repurposed.

Personally, I hope that we never have any form of named arguments in D (beyond whatever folks do with libraries, though I hope never have to deal with code that uses such libraries). But ultimately, that's going to be up to Walter and Andrei...

I do approve of the fact that this DIP doesn't automatically enable named arguments everywhere, since I really, really, really don't want to have parameters be part of the API if I can possibly avoid it, and I would never use @named anywhere if this DIP gets approved - though in all likelihood, that will result in arguments about whether folks should slap @named on functions or not between folks who want named arguments and those who don't. So, approval of the DIP with such an attribute could become pretty divisive with regards to how folks write libraries.

I'm not sure that you can punt the name mangling issue like the DIP currently does. It's currently legal to declare functions without even having parameter names (let alone requiring that the parameter names match) when you deal with stuff like .di files. It also affects what happens with functions that aren't extern(D). For instance, it's perfectly legal to put pure or nothrow on an extern(C) function declaration, and that affecs how the D code uses it, but it has no effect on the name mangling. If named arguments affect the name mangling, then they will only work with extern(D) functions, but if they don't, then you have issues when a function's declaration doesn't match its definition with regards to its parameters' names.

- Jonathan M Davis



February 27, 2019
On Sunday, 17 February 2019 at 17:09:57 UTC, Yuxuan Shui wrote:
> On Sunday, 17 February 2019 at 13:12:11 UTC, Rubn wrote:
>>
>> Allowing two functions to exist with the same type signature just adds unnecessary complexity.
>
> This is allowed, _right now_. This is not an addition made by this DIP. Example: https://d.godbolt.org/z/hbwsaU

That seems to be a misunderstanding of what that example does.  The first two declarations are just declaring that a function should exist with the signature `int fun(int, int)`.  The third declaration actually implements that function.

If OTOH you delete the implementation and use `dmd -c` to compile without linking, you'll get the expected overload-related error, whether or not you have the same or different parameter names, or no parameter names at all, in those first two declarations.
February 27, 2019
On Wednesday, 27 February 2019 at 02:17:30 UTC, Jonathan M Davis wrote:

> Personally, I hope that we never have any form of named arguments in D (beyond whatever folks do with libraries, though I hope never have to deal with code that uses such libraries). But ultimately, that's going to be up to Walter and Andrei...

Curious. How come?

Would it not be nicer for contributors to know what "TexPos(1, 1)" (from your dxml library) does without having to lookup TextPos? I actually got it wrong from just reading the source. I thought it was pixel positions x, y. But nope.

Another thing is that almost every time I see std.traits anywhere, I NEVER know which argument is what and always have to look it up. Multiply this by every programmer who has to code review, or maintain code and it's a lot of wasted time that's solved with proper use of named arguments.

Some arguments I have heard about against named arguments though:

1) verbosity of call-site - solvable when named arguments are optional, should the API designer think so. It's the same as if an API designer decides to call a publicly accessible property "config" or "configuration". If there's a function that takes one argument, it makes little sense for an API writer to force it to be named. But as long as that choice is given, the purpose is to make the function as natural as possible.

2) Parameter lock in - don't see how that's different than function name lock in. Choose a name, use it. It goes through code reviews. If you change it, you bump a version number. I guess the number of places where the api can break increases though. But from a number of years of experience, I have not experienced this. Plus, I tend to find that API "superficially" used named arguments

Example from std:

topN(r, 3)
topNCopy(r1, r2)
topNIndex(r1, i1)

These are the same function with different named arguments:

topN(r, 3)
topN(r, copy: r2)
topN(r, index: r2)

But since you don't have named arguments you put the name part of the arguments in the function name.

3) Needing to think about parameter names. You don't if they're optional. As the API designer. You need to think about the public interface of your function name anyway. And, if you're making public APIs, you're making docs (I hope). So you're already doing this. You would have to think if the API required named arguments or not though.

4) ??

Cheers,
- Ali
February 27, 2019
I would broadly second Jonathan's remarks above:
https://forum.dlang.org/post/mailman.7211.1551233866.29801.digitalmars-d@puremagic.com

... but a few thoughts in my own words.

First, I think my core objection to this proposal is that ultimately, it's a cosmetic change to language syntax that does not make any meaningful improvement to the kinds of programs one can write, or to the compiler's ability to prove their safety and correctness -- even allowing that it's opt-in, implementing support is going to be finnicky and intrusive, and risks nasty impacts on stuff that affects _all_ programs (e.g. name mangling).

If we consider the languages where named arguments are a feature, virtually all of them are scripting (or scriptable) languages where it's common to use them via a REPL, and the use-case is for functions that have a lot of parameters, where in the typical use-case the caller only wants to specify the ones that are non-default.

In a scripting language, it's convenient to allow the user to just make the one function call.  But in a systems programming language it's both straightforward and arguably better self-documenting to do something like:

```
struct Config
{
    // default values for everything
    int alpha = 23;
    double beta = 0.25;
    int gamma = 6;
    double delta = 1.5;
    // ...
    int omega = 99;
}

double foo (Config config)
{
    with(config) {
        // implementation
    }
}
```

and then one can call with e.g.:

```
Config config = { beta: 6.5, omega: 101 };
auto result = foo(config);
```

As others have already pointed out, it needs only some small improvements to the struct declaration mechanisms to allow us to do something like:

```
foo({ beta: 6.5, omega: 101 });
```

... without even needing to declare a separate Config instance.  This sort of approach will work naturally with UFCS:

```
double bar (int a, Config config) { ... }

x.bar({ delta: 9.125, gamma: 7});
```

... so one therefore has the effect of named parameters without any real change to the language syntax or behaviour.

On the question of "protecting against silent breakage in cases when a function's parameters are repurposed and renamed": this seems a very narrow protection compared to all the ways in which one can introduce breaking change into a function.  And by contrast it blocks something that can be very useful, which is renaming a function parameter to better illustrate its meaning, _without_ changing its purpose.

Specific feedback on a few points:

* `Completeness`: note that this approach of "all named or none" is
  in contrast with various languages' approach to named parameters,
  where it's common to have some initial obligatory parameters plus
  the option to set extra config variables.  Think Python, e.g. in
  this usage from the `pandas` data science library:

      dates = pd.date_range('20190227', periods=6)

  This should be noted as a contrast with what is being proposed
  in the current DIP.  (The struct-based approach outlined above
  may allow something closer to this, albeit imperfectly.)

* in the `Overloading and name mangling` section it would be good
  to have contrasting examples of what happens when parameter names
  are identical but types are different, e.g.:

      int add(int a, int b) {...}
      double add(double a, double b) {...}

  ... and a clear description of how template functions and methods
  will be impacted, e.g. `T add(T)(T a, T b)`.

* `Alternatives` should be updated to note the struct-based approach
  described above and by others, which does not need any specific
  support beyond perhaps improvements proposed in the DIP currently
  being drafted at
  https://github.com/wilzbach/DIPs/blob/b1283b455b635d7dcbc2c871d2aa47cc67190059/DIPs/DIP1xxx-sw.md

In summary:

* despite being opt-in only, the proposal still seems an intrusive change
  for limited practical benefit

* suggestions by others that named parameters should be opt-out would make
  it even more intrusive, and impose a massive unasked-for maintenance
  burden on existing library maintainers

* some small improvements to struct initialization would make it possible
  to get a syntax and behaviour very close to that wanted, while keeping
  entirely within existing idiomatic language syntax and style

Hope that helps!
February 27, 2019
On Friday, 15 February 2019 at 12:56:45 UTC, Mike Parker wrote:
> This is the feedback thread for the first round of Community Review for DIP 1019, "Named Arguments Lite":

The proposal mentioned that having two @named functions with same names and parameter types but different parameter names is allowed. However, this does imply @named functions have different mangling than a similar unnamed function. I think the DIP should mention whether this means that extern(!D) functions are forbidden altogether, or just don't consider parameter names in overload resolution.

The above brings this proposal closer to what Rikki did propose. IMO this proposal has better syntax, but Rikki's proposal has the advantage that named parameters can be combined with unnamed parameters. In any case, I think they should go to formal assesment together. Either one will be a step forward.