February 08, 2020
On 2/8/20 5:04 AM, Timon Gehr wrote:
> On 07.02.20 16:28, Steven Schveighoffer wrote:
>>>
>>> It does add the syntax, and I would argue it is not ideal if this fails to pass semantic analysis.
>>
>> Yes, it's valid syntax, but shouldn't pass semantic -- you named arguments that aren't present (AliasSeq does not have parameters named a b or c).
>> ...
> 
> So you are arguing that e.g., std.typecons.Proxy should fail to work with named arguments?

Technically, it doesn't today, so it's not a break. But it is a good point. opDispatch in general will fail to support named parameters without a ton of extra mixins and boilerplate (potentially, you could have opDispatch specify all parameters and names).

> 
>> But the DIP isn't 100% clear that named variadics cannot receive NamedParameter items. It says extra parameters match the "trailing ... of variadic parameter lists and Identifiers are not allowed". Not all variadic functions have a trailing ... without a name. I would think AliasSeq!(TList: 1, 2, 3) should be valid.
> 
> Why is that more useful than support for forwarding?

Not more useful, but unambiguous.

For example, what does AliasSeq!(TList: 1) mean? Did you mean to assign a 1 to the template parameter already named TList, or did you mean to submit a parameter named TList?

Should this then fail to compile or pass?
void foo(int a);
alias params = AliasSeq!(TList: 1);
foo(params); // does this mean foo(1) or foo(TList: 1)?

Potentially, we could specify with some syntax that a parameter could consume all named arguments not already tagged, and that name wouldn't matter. An interesting artifact of this, is that we could potentially eliminate std.typecons.Tuple.

But I feel this would be an additional proposal on top of named parameters, even though it's related.

-Steve
February 08, 2020
It's clear that what should happen with named arguments and variadics is far from clear-cut. Therefore, the proper way forward for the time being is to simply disallow matching them with a ...

Nothing is being broken by this, as currently named arguments do not work at all.

If a decent design for it is developed in the future, we can always add it. But adding a design now that turns out later to be inferior or botched is going to be hard to remove. Just look at the trouble we have with alias this and autodecoding.
February 09, 2020
On Friday, 7 February 2020 at 03:33:26 UTC, 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.

I am in definitely in favor of named arguments in the language. Overall I think the benefits of this specific DIP proposal outweigh the negatives identified.

That said, having parameter names automatically become part of a function's API is a meaningful downside. (Specifically, that a parameter name cannot be changed without risk of breaking existing callers.) The reasons are likely self-evident, but to spell out my thoughts:

* Additional design time when initially creating functions (good names are hard).
* More time required from code reviewers (both open-source and corporate).
* Barrier to incrementally improving a function (and documentation) over-time by improving the quality of the parameter names.

The above are more reflective of waterfall than an agile approach, a disadvantage in situations where a more iterative development style is preferable.

Another part of the equation is simply that when I'm developing a function, I usually have a pretty good idea whether named arguments are going to be a material benefit. In those cases I'm willing to spend time on the quality of the names.

I do think the benefits of the DIP outweigh this concern. However, if there is a reasonable way to allow the developer of a function to control whether the function can invoked via named arguments that would be an enhancement worth considering. This control need not be at the level of each individual parameter. It could be at the function level.

--Jon
February 09, 2020
On Sunday, 9 February 2020 at 00:56:15 UTC, Jon Degenhardt wrote:
> (Specifically, that a parameter name cannot be changed without risk of breaking existing callers.)

Does it change your view at all that parameter names are *already public* per both spec and reality and have been for a long, long time? (my web.d framework used their availability as early as 2012ish)

See item #6 here: https://dlang.org/spec/expression.html#IsExpression

"the parameter sequence of a function, delegate, or function pointer. This includes the parameter types, names, and default values."

And, of course, documentation though that isn't strictly part of the compiler breakage.
February 09, 2020
On Sunday, 9 February 2020 at 01:07:03 UTC, Adam D. Ruppe wrote:
> On Sunday, 9 February 2020 at 00:56:15 UTC, Jon Degenhardt wrote:
>> (Specifically, that a parameter name cannot be changed without risk of breaking existing callers.)
>
> Does it change your view at all that parameter names are *already public* per both spec and reality and have been for a long, long time? (my web.d framework used their availability as early as 2012ish)
>
> See item #6 here: https://dlang.org/spec/expression.html#IsExpression
>
> "the parameter sequence of a function, delegate, or function pointer. This includes the parameter types, names, and default values."
>
> And, of course, documentation though that isn't strictly part of the compiler breakage.

Probably not, but let me give some thoughts and ask a clarifying question.

Main thing - As a pragmatic matter, I'd expect it to be much more likely that named argument invocation would be a source of breakage than usage arising from introspection.

Related - There is significant difference between parameter names being public and having the names be sources of backward compatibility in function calls.

Now my question - I know function parameters names can be retrieved by type introspection. What I don't know is the ways those names can be used such that programs can break if a parameter names change. Can you give some examples?
February 09, 2020
On Sunday, 9 February 2020 at 01:47:35 UTC, Jon Degenhardt wrote:
> Now my question - I know function parameters names can be retrieved by type introspection. What I don't know is the ways those names can be used such that programs can break if a parameter names change. Can you give some examples?

We can do named parameters in a library already, something like:

void func(int param) { }

int item;

callNamed!(func, param => item)(); // possible today. It pulls param name of func and from the given lambda to match up the item.


If func's param name were to change, that callNamed would fail, just like with this dip.

Of course since the syntax is weird and you need to import a lib... I never use this thing and I doubt anyone else does either. (I can't even find my implementation right now, though I know I have it somewhere).

I do use it extensively for runtime things though like generating command line parsers and web apis which can break, but that's expected on that interface anyway so of course I design for it.

But my policy on breakage though is I avoid it... unless I specifically mention in the documentation that you can't rely on it. Then if you do, that's your problem. So if I didn't want to do reliable names, I'd just do

/// $(WARNING the parameter names are NOT stable and may change without notice. )

and then there we go, disclaimer of liability :)
February 09, 2020
On Sunday, 9 February 2020 at 02:03:42 UTC, Adam D. Ruppe wrote:
> On Sunday, 9 February 2020 at 01:47:35 UTC, Jon Degenhardt wrote:
>> Now my question - I know function parameters names can be retrieved by type introspection. What I don't know is the ways those names can be used such that programs can break if a parameter names change. Can you give some examples?
>
> We can do named parameters in a library already, something like:
>
> void func(int param) { }
>
> int item;
>
> callNamed!(func, param => item)(); // possible today. It pulls param name of func and from the given lambda to match up the item.
>
> If func's param name were to change, that callNamed would fail, just like with this dip.

That's a useful example, thanks! It doesn't change my overall opinion though. I like the DIP, even this downside. However, it would be an improvement if there was a way for the developer of a function to disable named parameter invocation.

Or perhaps a way to discourage it, for example, a compile-time warning about no-backward compatibility for parameter names.
February 09, 2020
On Sunday, 9 February 2020 at 02:15:36 UTC, Jon Degenhardt wrote:
> Or perhaps a way to discourage it, for example, a compile-time warning about no-backward compatibility for parameter names.

I would kinda love user-defined warnings. pragma(msg) comes close sometimes but there is no way to conditionally trigger it. (You can sort of conditionally disable via `version()` though.)

Of course, you could just name your parameters `_randomNameYouReallyDontWantToUse_like_seriously_dont_rely_on_this_name_lol` :P

A reasonable thing for the compiler to do btw would be to call out when function names change. Suppose you have:

foo(bar: 1, baz: 4)

and later you change the signature to

foo(int bar, int coolness)

the compiler could reasonably issue an error:

error: foo has no parameter named `baz`. Did you mean `coolness`?

based on process of elimination to suggest the names not yet specified to ease transition.
February 08, 2020
On 2/8/20 8:47 PM, Jon Degenhardt wrote:
> On Sunday, 9 February 2020 at 01:07:03 UTC, Adam D. Ruppe wrote:
>> On Sunday, 9 February 2020 at 00:56:15 UTC, Jon Degenhardt wrote:
>>> (Specifically, that a parameter name cannot be changed without risk of breaking existing callers.)
>>
>> Does it change your view at all that parameter names are *already public* per both spec and reality and have been for a long, long time? (my web.d framework used their availability as early as 2012ish)
>>
>> See item #6 here: https://dlang.org/spec/expression.html#IsExpression
>>
>> "the parameter sequence of a function, delegate, or function pointer. This includes the parameter types, names, and default values."
>>
>> And, of course, documentation though that isn't strictly part of the compiler breakage.
> 
> Probably not, but let me give some thoughts and ask a clarifying question.
> 
> Main thing - As a pragmatic matter, I'd expect it to be much more likely that named argument invocation would be a source of breakage than usage arising from introspection.
> 
> Related - There is significant difference between parameter names being public and having the names be sources of backward compatibility in function calls.
> 

If you name your parameters something unintuitive, like "a". Likely nobody is going to use them via named parameters.

For example, if you have;

Date makeDate(int year, int month, int day)

What would be the reason to change these? Likely you already picked those names.

But if you named them:

Date makeDate(int a, int b, int c)

Now, changing it to the more appropriate names as above would be technically a "breaking change". But who cares? Nobody is writing makeDate(b: 1, c: 2, a: 3), and if they are, they deserve broken code IMO.

I don't think there's going to be a lot of problems here. Take a look at the history of phobos and see if you can find places where someone changed an appropriate parameter name to another appropriate name. Chances are it's close to never. And even if it was changed, is the change something that would have to be made? Was the original parameter name so bad that it needed changing in light of the code breakage that would now take place?

The one annoying downside is that there is no possibly way to deprecate this. You can't have:

@deprecated("use better names please") Date makeDate(int a, int b, int c)
Date makeDate(int year, int month, int day)

This is one huge departure from current mechanisms.

-Steve
February 09, 2020
On Sunday, 9 February 2020 at 02:40:30 UTC, Steven Schveighoffer wrote:
> On 2/8/20 8:47 PM, Jon Degenhardt wrote:
>> On Sunday, 9 February 2020 at 01:07:03 UTC, Adam D. Ruppe wrote:
>>> On Sunday, 9 February 2020 at 00:56:15 UTC, Jon Degenhardt wrote:
>>>> (Specifically, that a parameter name cannot be changed without risk of breaking existing callers.)
>
> [...snip...]
>
> If you name your parameters something unintuitive, like "a". Likely nobody is going to use them via named parameters.
>
> For example, if you have;
>
> Date makeDate(int year, int month, int day)
>
> What would be the reason to change these? Likely you already picked those names.
>
> But if you named them:
>
> Date makeDate(int a, int b, int c)

Well, I personally wouldn't recommend this as a general remedy. Parameter names help to document the implementation. In many environments it's important that developers other than the original author be able to read, debug, enhance, or take over code. Having good parameter and variable names is helpful from this perspective. Naming conventions are a common element of coding standards for this reason.

In general, what I typically try to do (and recommend) is taking a good shot at creating meaningful names, but not spend excessive amounts of time on it. And, depending the situation, look at improving the names over time (and other elements of the code as well).

> I don't think there's going to be a lot of problems here. Take a look at the history of phobos and see if you can find places where someone changed an appropriate parameter name to another appropriate name. Chances are it's close to never.

For Phobos this would be my expectation as well. I'm admittedly thinking of project environments with meaningful size teams more than the standard library of a major programming language. Environments where there is a fair bit of code in earlier stages of development and subject to more evolution.