February 27, 2019
On Wednesday, 27 February 2019 at 12:49:52 UTC, Joseph Rushton Wakeling wrote:
> 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.

Virtually all of them is a bit of a simplification. C#, Kotlin, Swift, Dart, Objective-C are definitely not scripting languages and they aren't primarily used through repr, and they all support named/keyword arguments in some form.

> 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 });
> ```
>

This would be great.
February 27, 2019
On Wednesday, 27 February 2019 at 18:16:32 UTC, JN wrote:
> On Wednesday, 27 February 2019 at 12:49:52 UTC, Joseph Rushton Wakeling wrote:
>> ```
>> foo({ beta: 6.5, omega: 101 });
>> ```
>>
>
> This would be great.

It would be great indeed, but insufficient.

At least I can't find a reasonble struct based solution which handle default arguments correctly.

struct dim {
  uint w=5;
  uint h=5;
}

void foo(dim d={w:10, h:10}){}
void bar(dim d={w:20, h:20}){}

foo({w:50}); // h should default to 10 but it likely will be 5
bar({w:50}); // h should default to 20 but it likely will be 5

February 28, 2019
On Wednesday, 27 February 2019 at 12:49:52 UTC, Joseph Rushton Wakeling wrote:
> ...
> 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

Yes it does!! That is in fact the main argument for it! It allows the compiler to do a *much* better job at ensuring the correctness of programs, by attaching parameters to semantic labels instead of passing them by arbitrary positions and hoping that the type system will happen to catch errors.

> 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).
>

Only if you do it in a weird way. There's no *necessary* reason for named parameters to affect mangling at all.

> 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);
> ```

And even that is one case where named parameters represent a *huge* improvement!

If a new parameter is added to Config, there is *absolutely* no way to require it to be passed. You have to use something like my own `boilerplate.Builder()`, and even that just gives you an exception at compiletime.

struct Foo
{
  int a;
  int b;
  mixin(GenerateThis);
}

with (Foo.Builder())
{
  a = 2;
  return value; // runtime error: necessary field b not assigned
  // but no compile error because :( :( :(
}

There is *no way* to statically enforce that a field was set in a struct. Parameters on the other hand do this effortlessly. I'd *love* to ditch Boilerplate's generated builders and replace them with named parameters. The lack of named parameters is why that hacky expensive feature even exists to begin with.

>
> 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.
>

Yeah at the cost of breaking struct behavior, or you still don't have any way to have necessary parameters.

> 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.
>

I have literally never done that, whereas I reorder function parameters relatively often. Do you really rename function parameters more often than inserting a new required parameter in the middle?

February 28, 2019
On Thursday, 28 February 2019 at 08:32:22 UTC, FeepingCreature wrote:
> I have literally never done that, whereas I reorder function parameters relatively often. Do you really rename function parameters more often than inserting a new required parameter in the middle?

A function taking more than 2 parameters is a design flaw on its own, I think. Let alone adding new parameters _in_the_middle_ (shudder). You should almost always be better off taking a struct as parameter.
February 28, 2019
On Thursday, 28 February 2019 at 09:22:31 UTC, Dominikus Dittes Scherkl wrote:
> A function taking more than 2 parameters is a design flaw on its own, I think. Let alone adding new parameters _in_the_middle_ (shudder). You should almost always be better off taking a struct as parameter.

Considering D is billed as a multiparadigm language, I'd be surprised to hear that the intended usecase does not include "functions with more than two parameters". This comment seems quite far from practiced reality. In any case, passing a struct is a horrible solution, because, again, there is no way for structs to even enforce that *all* fields were set, let alone some subset, short of spamming Nullable.

February 28, 2019
On Wednesday, 27 February 2019 at 17:46:24 UTC, Dukc wrote:
> The proposal mentioned that having two @named functions with same names and parameter types but different parameter names is allowed.

No, it mentions that having two @named prototypes for the same functions with the same name and parameter types but different parameters is allowed.

eg: This is forbidden:

    @named:
    int foo(int x, int y) { return x + y; }
    int foo(int w, int z) { return w + z; }

and this is allowed:

    @named:
    int foo(int x, int y);
    int foo(int w, int z) { return y + z; }

The next iteration should probably make that distinction clearer.
March 01, 2019
On Wednesday, 27 February 2019 at 02:17:30 UTC, Jonathan M Davis wrote:
> 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 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 don't agree with this at all. The feature becomes all but useless, it's either all in or just don't include it. So many things are already part of the API, and this will be an opt-in feature for the user (not the library developer). The user can choose to use the variable names if they want, knowing full well if the author pleases they can change it, but this will be no different than changing the variable name of struct.

March 01, 2019
On Thursday, 28 February 2019 at 21:55:50 UTC, Olivier FAURE wrote:
> No, it mentions that having two @named prototypes for the same functions with the same name and parameter types but different parameters is allowed.
>
> eg: This is forbidden:
>
>     @named:
>     int foo(int x, int y) { return x + y; }
>     int foo(int w, int z) { return w + z; }
>
> and this is allowed:
>
>     @named:
>     int foo(int x, int y);
>     int foo(int w, int z) { return y + z; }
>
> The next iteration should probably make that distinction clearer.

Is the idea here that you can effectively define "aliases" for the parameter names (e.g. to help transitions), but not have multiple function implementations with the same type signatures and different names?

That presumably impacts back on the mangling question, and whether the parameter names need to be included in the function mangling ... ?
March 03, 2019
On Wednesday, 27 February 2019 at 18:51:40 UTC, Daniel N wrote:
> It would be great indeed, but insufficient.
>
> At least I can't find a reasonble struct based solution which handle default arguments correctly.
>
> struct dim {
>   uint w=5;
>   uint h=5;
> }
>
> void foo(dim d={w:10, h:10}){}
> void bar(dim d={w:20, h:20}){}
>
> foo({w:50}); // h should default to 10 but it likely will be 5
> bar({w:50}); // h should default to 20 but it likely will be 5

I wonder if you have a real-world example of this requirement (same named parameters but different requirements for defaults)?  I ask because it seems like the best way to address the concern is likely to be contingent on the particular use case.

The example given considers the input as a type encoding the set of parameter names and types, with default values as something extraneous.  It feels like that's the conceptual problem: the input type should encode parameter names, types, and defaults all together.

In other words, `foo` and `bar` should have different struct types (with different default values to their fields) as input.

Clunky and maybe a bit boilerplate-y?  Yes, but much less intrusive than introducing a syntax change that has significant impact on the maintainability of much already existing code.

Note that this would be simpler from a developer point of view if it was possible to declare "anonymous" structs in place in the function declarations, i.e.:

    int foo (struct { int w = 10; int h = 10; });
    int bar (struct { int w = 20; int h = 20; });

... which combined with the earlier suggestion would also be a fairly natural extension of existing struct syntax.
March 03, 2019
On Thursday, 28 February 2019 at 08:32:22 UTC, FeepingCreature wrote:
> Yes it does!! That is in fact the main argument for it! It allows the compiler to do a *much* better job at ensuring the correctness of programs, by attaching parameters to semantic labels instead of passing them by arbitrary positions and hoping that the type system will happen to catch errors.

This could sometimes be nice, but the question is whether the extra benefits are worth it compared to the problems caused by imposing a major semantic change on the language.

> If a new parameter is added to Config, there is *absolutely* no way to require it to be passed. You have to use something like my own `boilerplate.Builder()`, and even that just gives you an exception at compiletime.
>
> [... snip ...]
>
> There is *no way* to statically enforce that a field was set in a struct.

That's certainly a reasonable objection.  The question is not, does this cover _all_ use cases for named parameters, but does it cover some of the major ones that matter?  (For example, the case of multiple different parameters where one only wants to set the ones that need to be non-default.)

> Parameters on the other hand do this effortlessly. I'd *love* to ditch Boilerplate's generated builders and replace them with named parameters. The lack of named parameters is why that hacky expensive feature even exists to begin with.

I'm not familiar with your Boilerplate library, so difficult to comment -- are you saying here that the library's features could be implemented more straightforwardly (or with a nicer API for users) if named parameters were a thing?  Or that features of the library would not need to exist in the first place?

I ask because it's possible that the requirements here are arriving more out of preferences for how to write the downstream code, than about problems with writing idiomatically in D as it is right now.

> I have literally never done that, whereas I reorder function parameters relatively often. Do you really rename function parameters more often than inserting a new required parameter in the middle?

In what context do you reorder or insert new function parameters often?  In public functions or methods of a library?  In internals private to a library or app?  And what's the motivation for such re-ordering?

I ask because I wonder if there aren't other entirely adequate methods for managing those transitions that don't rely on named parameters, and which are more idiomatic to D as it already exists.  If you have concrete examples we could probably discuss those.

I accept that named parameters might make some of these transitions easier, but that has to be weighed against the disruption of introducing that feature to a language where a large amount of code has already been written without that feature in mind.