February 11, 2020
On Monday, 10 February 2020 at 19:38:34 UTC, Manu wrote:
> On Thu, Feb 6, 2020 at 7:34 PM Jonathan M Davis via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>
>> On Wednesday, February 5, 2020 11:08:59 PM MST Mike Parker via Digitalmars-d 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.
>>
>> - Jonathan M Davis
>
> I don't have any horse in this race... but I do just want to echo that
> I don't understand this feature at all.
> I don't know what it's for. I've never felt I wanted named arguments
> personally, and Jonathan's criticism feels very real to me.
>
> Here's a thought, which I haven't considered how it interacts with this DIP deeply, but it should be on the table:
>
> I do an immense amount of generative meta; generate wrappers, shims,
> bindings etc, which wrap existing functions.
> When the parameter names become part of the API, it means any such
> meta must pay extra attention to properly mirror the parameter names,
> and it must also carefully mirror the default args from the function
> it's wrapping.
> While most of my code takes care to do this anyway, there are cases
> where it's unnecessary and inconvenient. Some tasks can be completed
> with a tool like:
>
>   ReturnType!originalFunction wrapper(alias
> originalFunction)(Parameters!originalFunction args)
>   {
>     // special sauce...
>     return originalFunction(args);
>   }

Before the DIP you'd call that like:

wrapper(1, 2, 3);

After the DIP you'd call that like:

wrapper(1, 2, 3);

Or are you saying meta must mirror parameter names as well? If so why? You can't do the default args today anyway, and I'm not sure if it's ever been a problem?

I do agree that having something like ParametersWithNamesAndDefaultArgs is infeasible. Not only from a technical point of view but maintenance, programming burden, and migratory.
February 10, 2020
On Mon, Feb 10, 2020 at 4:05 PM Jonathan Marler via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Monday, 10 February 2020 at 23:20:34 UTC, Jonathan Marler wrote:
> > On Thursday, 6 February 2020 at 06:08:59 UTC, Mike Parker wrote:
> >> This is the feedback thread for the first round of Community Review for DIP 1030, "Named Arguments":
> >>
> >> https://github.com/dlang/DIPs/blob/44b0d4ec0da6a2e797ede748fb1e81cd6db10371/DIPs/DIP1030.md
> >>
> >> Here in the discussion thread, you are free to discuss anything and everything related to the DIP. Express your support or opposition, debate alternatives, argue the merits... in other words, business as usual.
> >>
> >> However, if you have any specific feedback for how to improve the the proposal itself, then please post it in the feedback thread. The feedback thread will be the source for the review summary I write at the end of this review round. I will post a link to that thread immediately following this post. Just be sure to read and understand the Reviewer Guidelines before posting there:
> >>
> >> https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md
> >>
> >> The review period will end at 11:59 PM ET on February 20, or when I make a post declaring it complete. Discussion in this thread may continue beyond that point.
> >>
> >> 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.
> >>
> >> Please stay on topic here. I will delete posts that are completely off topic.
> >
> > I'm curious what the current state of druntime/phobos is with
> > parameter name consistency.
> >  I took a quick look at std.math in phobos to see what some of
> > the current argument names are:
> >
> > auto conj(Num)(Num z) @safe pure nothrow @nogc
> > auto abs(Num)(Num x) @nogc pure nothrow
> > real cos(real x) @safe pure nothrow @nogc { pragma(inline,
> > true); return core.math.cos(x); }
> > auto sin(creal z) @safe pure nothrow @nogc
> > auto sin(ireal y) @safe pure nothrow @nogc
> >
> > So we have some of this:
> >
> > conj(z:someValue);
> > abs(x:someValue);
> > sin(y:someValue);
> >
> > Now that parameter names are apart of the function's API, this inconsistency starts to matter as changing it breaks the API. Will druntime/phobos try to come up with standard names for these situations?  Will we try to fix these names before integrating support for named parameters?  If we need to change names later, what will the policy be for druntime/phobos for making parameter name changes when inconsistencies are discovered?
> >
> > Also consider the case when overloads use different parameter names.  std.math.sin uses 'z' for creal arguments and 'y' for ireal arguments.  This can cause issues during refactor as one needs to re-check all parameter names when changing types of arguments. i.e.
> >
> > sin(z:someValue);
> >
> > If you change the type of someValue from creal to ireal, then this would still call the creal overload, perhaps unexpectedly.
>
> I took some time to go through the "std.array" module to see how many potential issues it might have.  Here's what I saw:
>
>
>
> -------------------------------------------------------------------------------
> different overloads of split use different parameter names
> -------------------------------------------------------------------------------
>
> > S[] split(S)(S s) @safe pure
> > auto split(alias isTerminator, Range)(Range range)
> > auto split(Range, Separator)(Range range, Separator sep)
>
> split(s: value);
> split(range: value);
>
> -------------------------------------------------------------------------------
> different overloads of "array" use different parameter names
> -------------------------------------------------------------------------------
>
> > ForeachType!Range[] array(Range)(Range r)
> > ForeachType!(PointerTarget!Range)[] array(Range)(Range r)
> > CopyTypeQualifiers!(ElementType!String,dchar)[]
> > array(String)(scope String str)
>
> array(r: value);
> array(str: value);
>
> -------------------------------------------------------------------------------
> Generic Range parameters use many different names 'r', 'range', 'ror', 'stuff', 's'
> -------------------------------------------------------------------------------
> > auto split(alias isTerminator, Range)(Range range)
> > ForeachType!Range[] array(Range)(Range r)
> > ForeachType!(PointerTarget!Range)[] array(Range)(Range r)
> > ElementEncodingType!(ElementType!RoR)[] join(RoR, R)(RoR ror,
> > scope R sep)
> > ElementEncodingType!(ElementType!RoR)[] join(RoR, E)(RoR ror,
> > scope E sep)
> > ElementEncodingType!(ElementType!RoR)[] join(RoR)(RoR ror)
> > T[] replace(T, Range)(T[] subject, size_t from, size_t to,
> > Range stuff)
> > ElementType!S[] replicate(S)(S s, size_t n)
>
> split(r: value);
> array(range: value);
> join(ror: value);
> replace(subject: value1, from: value2, to: value3, stuff: value4);
> replicate(s: value, n: 100);
>
> -------------------------------------------------------------------------------
> functions that take 2 arguments but have different parameter names
> -------------------------------------------------------------------------------
> > CommonType!(T[], U[]) overlap(T, U)(T[] a, U[] b) @trusted
> > pure nothrow bool sameHead(T)(in T[] lhs, in T[] rhs)
> > pure nothrow bool sameTail(T)(in T[] lhs, in T[] rhs)
>
> overlay(a: value1, b: value2);
> sameHead(lhs: value1, rhs: value2);
>
> -------------------------------------------------------------------------------
> sometimes an array is passed with 'a', sometimes with 'array', sometimes 'arr'
> -------------------------------------------------------------------------------
> > void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff)
> > auto staticArray(size_t n, T)(scope T a)
> > auto staticArray(size_t n, T)(scope T a, out size_t rangeLength)
> > Appender!(E[]) appender(A : E[], E)(auto ref A array)
> > RefAppender!(E[]) appender(P : E[]*, E)(P arrayPtr)
> > struct Appender(A)
> >     this(A arr) @trusted pure nothrow
>
> insertInPlace(array: value1, pos: value2, stuff: value3);
> staticArray(a: value);
> Appender(arr: value);
>
> -------------------------------------------------------------------------------
> Appender functions use inconsistent parameter names
> -------------------------------------------------------------------------------
> > struct Appender(A)
> >     void reserve(size_t newCapacity)
> >     private void ensureAddable(size_t nelems)
>
> appender.reserve(newCapacity: value);
> appender.ensureAddable(nelems: value);
>
> -------------------------------------------------------------------------------
> Sometimes "length" is spelled out, sometimes it is abbreviated to "len"
> -------------------------------------------------------------------------------
> > auto staticArray(size_t n, T)(scope T a, out size_t rangeLength)
> > private size_t appenderNewCapacity(size_t TSizeOf)(size_t
> > curLen, size_t reqLen) @safe pure nothrow
>
> staticArray(a: value, rangeLength: value2);
> appenderNewCapacity(curLen: 100, reqLen: 200);
>
> -------------------------------------------------------------------------------
> appender overloads use different parameter names
> -------------------------------------------------------------------------------
> > Appender!(E[]) appender(A : E[], E)(auto ref A array)
> > RefAppender!(E[]) appender(P : E[]*, E)(P arrayPtr)
>
> appender(array: value);
> appender(arrayPtr: value);

Mmmm, wow.
Yeah, it seems an important pre-req for this DIP to be accepted is
that all standard libraries should have a major pass to make sure all
parameter names are dignified names that we can confidently stand
behind for the rest of time, and also that standard names for common
parameters are decided and proliferated.
"There are 2 hard problems in computer science..."
February 11, 2020
On Monday, 10 February 2020 at 23:48:05 UTC, Manu wrote:
> Ummm... you're saying bad API names has a "very low probability"? Finish this sentence: "There are 2 hard problems in computer science..."

Off by 1 errors?

:)

>
> I mean, I'm constantly tweaking API's for intuitive appeal. Programmers do this _all the time_.

Agreed. If it's any conciliation (i assume probably not but anyway), in swift you take a little bit more time to name things, but in my experience maintainability goes up 10x. Also, it has not really been an issue when doing scala or kotlin.

>
>> We literally have two named arguments DIP that are postponed for this DIP. The discussion has been made so many times already in which your concerns and objections has brought up time and time again. Which frankly I don't have time nor the energy to argue in favor it again when you can look into those discussions threads already.
>
> I've never posted a single comment in a named argument thread. It's
> just not a thing I care about.
> I commented today because I feel like this DIP has a high probability
> of acceptance (because Walter wrote it), and I wanted to understand
> what was about to happen.
>
> I'm still mostly ambivalent about this, but I'm concerned you're still
> carefully avoiding my key concern; I showed an entire class of code
> that will be broken, you need to have a response to that.
> Basically everything I've ever written in a professional capacity will
> cease working if clients can call with named arguments.
>
>> There is no apocalypse scenario in C# community, when it comes to named arguments.
>
> They didn't have a decade of existing and important code that will break.

C# didn't get named params till 2009 it seems (version 4.0).

February 11, 2020
On Monday, 10 February 2020 at 23:20:34 UTC, Jonathan Marler wrote:
> Now that parameter names are apart of the function's API,

I'm not sure it's correct to say this, considering that parameter names have already been accessible using reflection for a while now. This is what allowed library implementations of named arguments to work. As such, effectively this DIP just adds some syntax sugar.

February 11, 2020
On Tuesday, 11 February 2020 at 00:03:01 UTC, aliak wrote:
> I do agree that having something like ParametersWithNamesAndDefaultArgs is infeasible.

I posted this earlier in this very thread:

https://forum.dlang.org/post/cfcgecteoeynumsamjwe@forum.dlang.org

It is not only feasible... but trivial. ParametersWithNamesAndDefaultArgs is a *built-in language feature* - see 5.6 under here https://dlang.org/spec/expression.html#IsExpression

Forwarding this stuff is not difficult at all.
February 11, 2020
On Monday, 10 February 2020 at 23:48:05 UTC, Manu wrote:
> I showed an entire class of code that will be broken, you need to have a response to that.

Take a look at how easy it is to write a full forwarder function:

https://forum.dlang.org/post/cfcgecteoeynumsamjwe@forum.dlang.org

Note that the parameter names of the wrapper as seen from the outside (or even the inside if you fetch it off that tuple) are identical to the original.

This has been defined in the language for years.
February 11, 2020
On Tuesday, 11 February 2020 at 00:40:58 UTC, Adam D. Ruppe wrote:
> On Tuesday, 11 February 2020 at 00:03:01 UTC, aliak wrote:
>> I do agree that having something like ParametersWithNamesAndDefaultArgs is infeasible.
>
> I posted this earlier in this very thread:
>
> https://forum.dlang.org/post/cfcgecteoeynumsamjwe@forum.dlang.org
>
> It is not only feasible... but trivial. ParametersWithNamesAndDefaultArgs is a *built-in language feature* - see 5.6 under here https://dlang.org/spec/expression.html#IsExpression
>
> Forwarding this stuff is not difficult at all.

Oh. Indeed :) Seems simple enough.

But that darned __parameters thing. It's the devil. Reminded me of the first time I encountered that insomnia inducer, courtesy of H. S. Teoh (thanks HST) - https://forum.dlang.org/post/mailman.1565.1379620490.1719.digitalmars-d-learn@puremagic.com
February 10, 2020
On Tue, Feb 11, 2020 at 12:58:23AM +0000, aliak via Digitalmars-d wrote: [...]
> But that darned __parameters thing. It's the devil. Reminded me of the
> first time I encountered that insomnia inducer, courtesy of H. S. Teoh
> (thanks HST) -
> https://forum.dlang.org/post/mailman.1565.1379620490.1719.digitalmars-d-learn@puremagic.com

Whoa.  Just last week I was trying to look up this exact post, but couldn't, and now you show up with a convenient direct link to it.  :-D Thanks!!

And yeah, __parameters must be one of the darkest corners of D with the strangest, quirkiest semantics that anybody can imagine. It took me a LOT of trial-and-error and staring at Phobos code before I figured out that arcane black magic. (And even then, I'm still not 100% sure I got it all right...)


T

-- 
Life is complex. It consists of real and imaginary parts. -- YHL
February 11, 2020
On Tuesday, 11 February 2020 at 01:18:08 UTC, H. S. Teoh wrote:
> It took me a LOT of trial-and-error and staring at Phobos code before I figured out that arcane black magic.

Getting individual pieces out of it need some techniques (gotta use the slice technique to get param UDAs too btw). It isn't bad once you know them, but yeah, you aren't going to magically know it without help.

But doing it to *forward* like Manu wants is *very* easy. Then you just treat it as a single block and it ALL automatically just works! This isn't impossible, it isn't error-prone, it isn't even particularly verbose. It is just one thing to use.
February 11, 2020
On Friday, 7 February 2020 at 03:33:26 UTC, 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've had the opportunity to design some methods relying on named arguments in C#. I've come to the conclusion that this issue with methods having too many arguments comes from parameters being positional.

I find the old advice to package it into a structure as pretending like you're reducing the number of arguments.

While a method with many arguments would indicate doing too many things, but I think as you move up in the call stack you have to add to all the different functionality you're trying to abstract away.