February 11, 2020
On Tue, Feb 11, 2020 at 5:30 AM Arine via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Tuesday, 11 February 2020 at 09:46:35 UTC, Paolo Invernizzi wrote:
> > Let's put It simple, and let's boil this down to essential: there's MORE probability of FUTURE breakage with named parameters, and that's a fact.
>
> Only if you use the feature. That's part of the reason why I don't think you should be able to set a default of the middle argument. This just forces someone to use the feature if they want a default parameter. Neither C# nor Python allow you to set a default parameter in the middle without the rest that follow also having default values.
>
> Other than that, if you don't want your code to break potentially from argument changes, then don't use named parameters.

As a library author, you can't control whether a client uses named
arguments or not. You must assume that they might use them anywhere
and everywhere.
This is huge for phobos and druntime, which should have a major pass
over all function argument names to achieve dignity before we set them
in stone.
February 11, 2020
On 2/11/2020 5:52 AM, Steven Schveighoffer wrote:
> An example:
> 
> foo(a: 1, b:2);
> 
> Now I want to replace all calls to foo with a special wrapper that logs all calls.
> 
> alias foo = logCalls!(.foo);
> 
> foo(a: 1, b:2); // error, cannot use named parameters with tuples.
> 
> Is there a plan to mitigate this limitation?

Currently, no.

The current plan is named arguments will not match to ...

This leaves the door open to a future enhancement along those lines, which is better than trying to gin up an awkward solution.
February 11, 2020
On 2/11/20 2:07 PM, Walter Bright wrote:
> On 2/11/2020 5:52 AM, Steven Schveighoffer wrote:
>> An example:
>>
>> foo(a: 1, b:2);
>>
>> Now I want to replace all calls to foo with a special wrapper that logs all calls.
>>
>> alias foo = logCalls!(.foo);
>>
>> foo(a: 1, b:2); // error, cannot use named parameters with tuples.
>>
>> Is there a plan to mitigate this limitation?
> 
> Currently, no.
> 
> The current plan is named arguments will not match to ...
> 
> This leaves the door open to a future enhancement along those lines, which is better than trying to gin up an awkward solution.

I disagree. If you don't do something about this, the entire realm of wrapping types and functions becomes convoluted and sometimes impossible, because you can't wrap things and have them behave as the original thing as easily as you can today.

If we can't figure out a solution, I would say we hold off on named parameters. D's major strength is compile-time introspection and code generation, and this DIP adds a whole new aspect of API that is off-limits to introspection.

-Steve
February 11, 2020
On Monday, February 10, 2020 11:27:49 AM MST Steven Schveighoffer via Digitalmars-d wrote:
> On 2/6/20 10:33 PM, Jonathan M Davis wrote:
> > Once in a while, named arguments may
> > be useful, but for the most part, they're useful because a function has
> > way too many parameters, in which case, the function should have been
> > designed differently.
>
> I find this assertion lacking evidence.
>
> How does one design a constructor that initializes all the fields of a type without including all the parameters to initialize that type? If you reduce the number of parameters, what do you do with the data not specified? I suppose you can just have a minimal constructor and then just expect the user to set all the pieces up, but what if you need to use it in an expression? How do you decide which pieces are "important" enough to initialize first, and which ones get initialized later? What if the parameters are initializing things that can only be initialized in the constructor (e.g. immutable data).
>
> I focus on constructors because structs ALREADY support named parameters in this instance (when there is a lack of constructor), and we haven't seen the problems you are asserting.
>
> I can imagine with this DIP instead of 15 different constructors for all the different ways you want to construct said type (yes, I've seen this kind of stuff), you have one that has default arguments for all of the optional pieces (or maybe you split them up with ones that can be safe/pure and ones that can't, etc). And then the call interface is much better looking and self-explanatory. And I like that you can pick which way you want to call it, even for individual parameters.

The only time that the struct initialization equivalent of named parameters comes into play is when you have a POD type which exposes its member variables. Most structs don't do that, because it's usually bad practice to expose members that way unless they're POD types, and most structs aren't POD types. They usually encpasulate their data and have functions for manipulating it. So, while struct initializers may exist in the language, they're very limited in how they can be used, whereas named arguments could be used pretty much anywhere.

I have rarely seen structs where it made sense to have a long list of parameters to their constructors. In almost all cases, when that sort of thing happens, it makes far more sense to group such data into multiple structs so that the data is more organized instead of a huge blob of values all shoved directly into a single object. And in general, if a function parameter list is long, it's usually because the API didn't use structs to group and encapsulate data cleanly. I have rarely seen code where I would have considered it reasonable to have a large list of parameters to a function. As far as I can tell, named parameters are primarily an excuse to be able to have overly long parameter lists instead of properly organizing data, and they encourage what I would consider to be poor programming practices.

Regardless, my biggest problem with this DIP (and any DIP with named arguments) is that it adds function parameter names to the API. IMHO, it adds minimal benefit, and in return, it adds yet another set of names which are going to be bikeshedded, and yet another thing that you can't change without risking breaking code. If D were set up so that you normally had function prototypes separate from the functions themselves like you do in C/C++, I would almost certainly stop putting names on _any_ function prototypes if named parameters were added. I don't want to have to worry about breaking someone else's code because of a change to a parameter's name, and IMHO, there are already far too many arguments over the names of functions and types without adding parameter names to the list.

- Jonathan M Davis



February 11, 2020
On Friday, February 7, 2020 8:57:56 PM MST Walter Bright via Digitalmars-d wrote:
> On 2/6/2020 7:33 PM, Jonathan M Davis wrote:
> > Well, I'll say again that I don't like the idea of having named arguments in the language, because it makes the parameter names part of the API, resulting in yet more bikeshedding and yet another thing that can't be changed without breaking existing code. Once in a while, named arguments may be useful, but for the most part, they're useful because a function has way too many parameters, in which case, the function should have been designed differently.
> >
> > Unfortunately, since it's Walter who created the DIP, and a number of people do like the idea of named arguments, I expect that some form of this will make it in, but I still think that it's a bad idea.
>
> I appreciate your thoughts on this. But I like the feature even if all it does is make the "Flag" template obsolete:
>
>    https://dlang.org/library/std/typecons/flag.html
>
> So instead of:
>
>    foo(Yes.caseSensitive)
>
> we'd write:
>
>    foo(caseSensitive : true)
>
> There's no overhead or cognitive load of an extra type, and it doesn't look stupid.

That is an upside to it, though I don't think that it's worth having to deal with named arguments in general just get rid of Flag. I confess though that I've always thought that Flag was an unnecessary complication and have only used it because people have been insisting that it's best practice. I never use it in code that isn't in a library that I'm writing for other people to use. If you're familiar with the function, then a naked bool is enough to understand what the function call is doing and no sort of argument name at the call site is necessary. If you aren't familiar with the function, then you should be reading its documentation anyway instead of assuming that you understand what it does based simply on what it's called or what the names of its arguments are. And in that sense, named arguments seem to me like a further excuse to try to claim that you don't need to actually read the documentation to understand what functions do, which ultimately leads to shooting yourself in the foot when you make an assumption that doesn't match the assumptions that the function's author made.

- Jonathan M Davis



February 12, 2020
On Wednesday, 12 February 2020 at 05:03:49 UTC, Jonathan M Davis wrote:
> If you're familiar with the function, then a naked bool is enough to understand what the function call is doing and no sort of argument name at the call site is necessary. If you aren't familiar with the function, then you should be reading its documentation anyway instead of assuming that you understand what it does based simply on what it's called or what the names of its arguments are.

This strikes me as a false dichotomy, in two ways.

1) It's entirely possible to be familiar enough with a function to understand what it does, but not so familiar that you have every detail of its parameter list memorized. For example, if I see `stdin.byLine(true)`, I may remember that the boolean argument has to do with whether it keeps or drops newlines, but not be sure which behavior `true` corresponds to. `stdin.byLine(keepTerminator: true)` makes it immediately obvious.

2) While function and argument names certainly communicate *less* information than documentation does, the amount they communicate is not zero. For example, if I'm reading some code in an unfamiliar language, and I see something like `Math.abs(x)`, I have a pretty good idea what that means even without looking at the documentation, because the name refers to an existing piece of background knowledge I possess.

Names can't tell you everything, of course. If you need to know more, you can (and should) refer to the documentation, or failing that, the source code. But sometimes, you don't need to know everything, and in those situations, being able to get what you need from names is far more convenient than having to search the documentation every time.
February 12, 2020
On Wednesday, 12 February 2020 at 05:03:49 UTC, Jonathan M Davis wrote:
> On Friday, February 7, 2020 8:57:56 PM MST Walter Bright via Digitalmars-d wrote:
>> On 2/6/2020 7:33 PM, Jonathan M Davis wrote:
>> > Well, I'll say again that I don't like the idea of having named arguments in the language, because it makes the parameter names part of the API, resulting in yet more bikeshedding and yet another thing that can't be changed without breaking existing code. Once in a while, named arguments may be useful, but for the most part, they're useful because a function has way too many parameters, in which case, the function should have been designed differently.
>> >
>> > Unfortunately, since it's Walter who created the DIP, and a number of people do like the idea of named arguments, I expect that some form of this will make it in, but I still think that it's a bad idea.
>>
>> I appreciate your thoughts on this. But I like the feature even if all it does is make the "Flag" template obsolete:
>>
>>    https://dlang.org/library/std/typecons/flag.html
>>
>> So instead of:
>>
>>    foo(Yes.caseSensitive)
>>
>> we'd write:
>>
>>    foo(caseSensitive : true)
>>
>> There's no overhead or cognitive load of an extra type, and it doesn't look stupid.
>
> That is an upside to it, though I don't think that it's worth having to deal with named arguments in general just get rid of Flag. I confess though that I've always thought that Flag was an unnecessary complication and have only used it because people have been insisting that it's best practice. I never use it in code that isn't in a library that I'm writing for other people to use. If you're familiar with the function, then a naked bool is enough to understand what the function call is doing and no sort of argument name at the call site is necessary. If you aren't familiar with the function, then you should be reading its documentation anyway instead of assuming that you understand what it does based simply on what it's called or what the names of its arguments are. And in that sense, named arguments seem to me like a further excuse to try to claim that you don't need to actually read the documentation to understand what functions do, which ultimately leads to shooting yourself in the foot when you make an assumption that doesn't match the assumptions that the function's author made.

Named arguments is the difference between spending 1 second looking at this:

makeWindow(x: 67, y: 98, width: 100, height: 100)

Or taking about 1 to 5 minutes depending on how easy documentation is to find, and how bored you are to figure out what this is doing:

makeWindow(67, 98, 100, 100)

The 1 to 5 minutes is guesstimate work. But there's a lot of research out there about human task behavior. E.g. you have about 2-3 minutes of someone's attention before you switch tasks. It can take anywhere from a minute to 20 to get back to what you were doing after a context switch. Looking up and searching for documentation unnecessarily is most certainly a context switch. Add the fact that many libraries do not have documentation or poor documentation, that means browsing the source code. Throw in attention spans and anything you can do to make code readable/reviewable is a huge win to productivity.

Unless you're a lone programmer working on your own project consistently this doesn't apply. But even then if you switch between projects it does, because there's no way you're remember what every bool or int parameter does.

Coding in the professional world is mostly social. The languages that make it more social and help that aspect will win the long game.

>
> - Jonathan M Davis


February 12, 2020
On Wednesday, 12 February 2020 at 07:42:32 UTC, aliak wrote:
> Named arguments is the difference between spending 1 second looking at this:
>
> makeWindow(x: 67, y: 98, width: 100, height: 100)
>
> Or taking about 1 to 5 minutes depending on how easy documentation is to find, and how bored you are to figure out what this is doing:
>
> makeWindow(67, 98, 100, 100)

You're using an example in favor of a point, because it's hard to someone use constants for this kind of thing for a production code, at least for obvious reasons it shouldn't.

Now let's compare:

> makeWindow(x: 67, y: 98, width: 100, height: 100)

With:

makeWindow(x, y, width, height);

Of course 'x', 'y', 'width' and 'height' are variables defined elsewhere, but it's less noisy.

Now to be honest I would prefer for this particular function to use a struct like "myWindow" to define the coordinates:

makeWindow(myWindow);

I barely use name parameters for languages that support and to be honest I barely see than in other codes.

IDE are pretty much advanced these days, and if I need to check out at least in VS it shows me everything that I need about the arguments (Names, Types...).

Sasha.
February 12, 2020
On Tuesday, 11 February 2020 at 19:07:23 UTC, Walter Bright wrote:
> On 2/11/2020 5:52 AM, Steven Schveighoffer wrote:
>> An example:
>> 
>> foo(a: 1, b:2);
>> 
>> Now I want to replace all calls to foo with a special wrapper that logs all calls.
>> 
>> alias foo = logCalls!(.foo);
>> 
>> foo(a: 1, b:2); // error, cannot use named parameters with tuples.
>> 
>> Is there a plan to mitigate this limitation?
>
> Currently, no.
>
> The current plan is named arguments will not match to ...
>
> This leaves the door open to a future enhancement along those lines, which is better than trying to gin up an awkward solution.

Sorry but this is another half backed implementation.

Sasha.
February 12, 2020
On 2/12/20 2:44 PM, SashaGreat wrote:
> On Wednesday, 12 February 2020 at 07:42:32 UTC, aliak wrote:
>> Named arguments is the difference between spending 1 second looking at this:
>>
>> makeWindow(x: 67, y: 98, width: 100, height: 100)
>>
>> Or taking about 1 to 5 minutes depending on how easy documentation is to find, and how bored you are to figure out what this is doing:
>>
>> makeWindow(67, 98, 100, 100)
> 
> You're using an example in favor of a point, because it's hard to someone use constants for this kind of thing for a production code, at least for obvious reasons it shouldn't.
> 
> Now let's compare:
> 
>> makeWindow(x: 67, y: 98, width: 100, height: 100)
> 
> With:
> 
> makeWindow(x, y, width, height);
> 
> Of course 'x', 'y', 'width' and 'height' are variables defined elsewhere, but it's less noisy.

I agree with you! But it depends on the situation.

I'll embelish with something else.

Let's say that you have variables for some and you want to put in literals for others, which do you prefer?

makeWindow(67, 98, width, height)

or

makeWindow(x: 67, y: 98, width, height)

You see, you can use named parameters when it makes sense, and not when it doesn't. I think this is really just a greater mechanism to make calls more self-documenting, and code much easier to read and understand.

> Now to be honest I would prefer for this particular function to use a struct like "myWindow" to define the coordinates:
> 
> makeWindow(myWindow);

This is just named parameters with extra types needed. Same as the Flag case. Removing all that cruft from the library and language is a net-win.

And it doesn't help when you want to use expressions to generate new parameters -- the code is going to be ugly because you first have to construct a typeof(myWindow).

> I barely use name parameters for languages that support and to be honest I barely see than in other codes.

My second most used language is Swift, which requires named parameters. There are some cool things you can do with function and parameter names when they are significant. I think it's going to be a net benefit. We just have to resolve the introspection issue.

-Steve