February 07, 2020
On Fri, Feb 07, 2020 at 07:59:41PM +0000, matheus via Digitalmars-d wrote:
> On Friday, 7 February 2020 at 19:26:10 UTC, H. S. Teoh wrote:
> > ...
> > However, I *have* also found myself desiring nameable arguments for
> > the sake of self-documenting code, for example:
> > 
> > 	myRange.process(nRetries: 2);
> > 
> > as opposed to:
> > 
> > 	myRange.process(2); // what does '2' mean?!
> > ...
> 
> Yes this is one case that people will argue in favor of named arguments, but on the other hand I would point out: Why is he using a magic number in a code? :)

<rant>

IMNSHO, the obsession with getting rid of magic numbers is a bunch of hooey.  There's a time and place for that, e.g., you don't want two pieces of code to go out of sync when the constants they use must match a common value.  But pushing this to the extremes leads to stupid code like this:

	enum two = 2; // look, ma! I know how to name magic numbers!
	myRange.process(two); // yay, no more magic numbers!

which is completely ridiculous.

If the constant only appears in one place, just write the damn constant out already, that's why the programming language has integer literals, dammit. Giving it a name just because "magic numbers are Bad(tm)" is stupid.

</rant>


[...]
> https://docs.microsoft.com/en-us/dotnet/api/system.dayofweek?view=netframework-4.8#examples
> 
> You will see a example of DateTime usage like this:
> 
> > // Assume the current culture is en-US.
> > // Create a DateTime for the first of May, 2003.
> >    DateTime dt = new DateTime(2003, 5, 1);
> 
> They didn't even bother to use named arguments there. They just warned about culture en-US. :)

Actually, that's not en-US. In *true* American style, the correct order of arguments should be (5, 1, 2003). :-P

(Which IMNSHO is a stupid, illogical convention, which gets especially bad when they drop the first 2 digits of the year, and then you get incomprehensible dates like 10/12/11: is it Oct 12, 2011? Dec 10, 2011? Or Dec 11, 2010?  Or maybe Nov 12, 2010? Who even knows. Everyone should just stick with ISO-style yyyy-mm-dd, dangit!!)


> Well in my opinion I would prefer to see development in other areas than in this particular case.
[...]

True, Walter himself has said D needs to have a small number of powerful tools that are very expressive, rather than be a kitchen sink full of every feature you can think of but each is anemic and more-or-less redundant.


T

-- 
Do not reason with the unreasonable; you lose by definition.
February 07, 2020
On Friday, 7 February 2020 at 21:57:18 UTC, H. S. Teoh wrote:
> On Fri, Feb 07, 2020 at 07:59:41PM +0000, matheus via Digitalmars-d wrote:
>> On Friday, 7 February 2020 at 19:26:10 UTC, H. S. Teoh wrote:
>> > ...
>> > However, I *have* also found myself desiring nameable arguments for
>> > the sake of self-documenting code, for example:
>> > 
>> > 	myRange.process(nRetries: 2);
>> > 
>> > as opposed to:
>> > 
>> > 	myRange.process(2); // what does '2' mean?!
>> > ...
>> 
>> Yes this is one case that people will argue in favor of named arguments, but on the other hand I would point out: Why is he using a magic number in a code? :)
>
> <rant>
>
> IMNSHO, the obsession with getting rid of magic numbers is a bunch of hooey.  There's a time and place for that, e.g., you don't want two pieces of code to go out of sync when the constants they use must match a common value.  But pushing this to the extremes leads to stupid code like this:
>
> 	enum two = 2; // look, ma! I know how to name magic numbers!
> 	myRange.process(two); // yay, no more magic numbers!
>
> which is completely ridiculous.
>...

Hold your rant buddy I was just replying to your example :)

>> > 	myRange.process(2); // what does '2' mean?!

But of course seeing a code like:

> 	enum two = 2; // look, ma! I know how to name magic numbers!
> 	myRange.process(two); // yay, no more magic numbers!

Would be totally nonsense to me too. On the other hand:

> 	myRange.process(nRetries);

For me would be ok and a standard where I work. And the IDE would give me the hint about the value of nRetries.

Talking about magic numbers, well I had enough of it after diving into code like[1]:

> tempy = 0x80000000;
> for(i=-131072;i<=131072;i+=(2048>>gride))

> plc = x1+mulscale12((2047-y1)&4095,inc);
> i = ((y1+2048)>>12); daend = ((y2+2048)>>12);

And need to understand each number. :)

Matheus.

[1] - https://github.com/videogamepreservation/dukenukem3d/blob/master/SRC/ENGINE.C
February 07, 2020
On Fri, Feb 07, 2020 at 10:28:27PM +0000, matheus via Digitalmars-d wrote: [...]
> Hold your rant buddy I was just replying to your example :)

I know. But you struck a nerve. ;-)


> > > > 	myRange.process(2); // what does '2' mean?!
> 
> But of course seeing a code like:
> 
> > 	enum two = 2; // look, ma! I know how to name magic numbers!
> > 	myRange.process(two); // yay, no more magic numbers!
> 
> Would be totally nonsense to me too. On the other hand:
> 
> > 	myRange.process(nRetries);
> 
> For me would be ok and a standard where I work. And the IDE would give me the hint about the value of nRetries.

Fair enough. But it seems a bit onerous to have to write this:

	int nRetries = 2;
	myRange.process(nRetries);

when you could just write:

	myRange.process(nRetries: 2);


> Talking about magic numbers, well I had enough of it after diving into code like[1]:
> 
> > tempy = 0x80000000;
> > for(i=-131072;i<=131072;i+=(2048>>gride))
> 
> > plc = x1+mulscale12((2047-y1)&4095,inc);
> > i = ((y1+2048)>>12); daend = ((y2+2048)>>12);
> 
> And need to understand each number. :)

I see nonsense like this all the time. It's common practice in "enterprise" code. It's one of the red flags that says "don't touch this spaghetti code unless you can eat the consequences". My policy is to stay away from such code unless you absolutely can't get out of touching it.  And even then, touch as little as you can to get your job done, and then get outta there pronto, before the fragile tower of cards that is the code comes crashing down on your head. :-P

In this particular case, clearly the constants aren't just one-off constants; they have a specific meaning and really should be refactored into named constants instead.  So in this case, I'd say it's a *good* thing to get rid of the magic numbers.

But I disagree with the hardline attitude of "there must be no integer literals in your code outside of constant declarations", which is apparently what some people actually believe.  In each case, a judgment call must be made, and there is no one-size-fits-all answer.  As Walter said once:

	I've been around long enough to have seen an endless parade of
	magic new techniques du jour, most of which purport to remove
	the necessity of thought about your programming problem.  In the
	end they wind up contributing one or two pieces to the
	collective wisdom, and fade away in the rearview mirror.

You cannot just take a rule of thumb like "avoid magic constants" as a crutch to avoid the necessity of thought about your present programming problem. Sometimes it makes sense, but sometimes it doesn't; it doesn't make any sense to have a knee-jerk reaction "aaaaah, magic constant!" every time you see a naked integer literal.


T

-- 
Obviously, some things aren't very obvious.
February 08, 2020
On Friday, 7 February 2020 at 19:44:31 UTC, bachmeier wrote:
> On Friday, 7 February 2020 at 19:02:14 UTC, matheus wrote:
>
>> "...named arguments may be useful, but for the most part, they're useful because a function has way too many parameters, the function should have been designed differently.".
>
> It actively encourages a style of "just add another function argument". You start small and as you decide to change your function, it's easy to fall into the trap of adding one more argument, because the end user is free to ignore it.

People will do this anyway, whether or not the language has named arguments. In fact, here are a couple examples in D where it's been done in the past:

- https://github.com/dlang/dmd/pull/8195
- https://github.com/dlang/druntime/pull/2376

At least with named arguments, I have the option of writing `destroy!(initialize: false)(foo)`, instead of just `destroy!false(foo)`.
February 07, 2020
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.
February 08, 2020
On Saturday, 8 February 2020 at 03:57:56 UTC, Walter Bright 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.

Honestly, I like the Flag template ...

I think Jonathan have nailed the point:. In my little, I've a PR waiting for months as it breaks a possible derived class of Phobos Socket, as none is marking methods 'final' when it's not intended to be part of the API. And that remember me that, once alone a time, you and Andrei agreed that turning the default to 'final' from 'virtual' was the correct thing to do, specifically for the above point: the default should encourage the writing of a "minimalist" API boundary.

Now, I'm all with Jonathan on that, having the parameters name part of the API is just going in the wrong direction related to the above: we are enlarging the possibility of code breakage. Do we want to go further down that road?
February 08, 2020
On 2/8/2020 12:42 AM, Paolo Invernizzi wrote:
> Now, I'm all with Jonathan on that, having the parameters name part of the API is just going in the wrong direction related to the above: we are enlarging the possibility of code breakage. Do we want to go further down that road?

This PR would discourage gratuitous name changes of parameters, just like changing the name of a function causes breakage. The problem is easily avoided - don't change the parameter names.

It's not the same thing as changing the behavior.
February 08, 2020
On Saturday, 8 February 2020 at 08:42:57 UTC, Paolo Invernizzi wrote:
> I think Jonathan have nailed the point:. In my little, I've a PR waiting for months as it breaks a possible derived class of Phobos Socket, as none is marking methods 'final' when it's not intended to be part of the API. And that remember me that, once alone a time, you and Andrei agreed that turning the default to 'final' from 'virtual' was the correct thing to do, specifically for the above point: the default should encourage the writing of a "minimalist" API boundary.


I'm sorry, I need to hammer this in.

A nameless API is not minimal. An API is not made more minimal by ignoring the names! The *meaning* of parameters is part of the API! If you have a function DateTime(1, 2, 3), then you already have a function DateTime that takes day, month and year, whether or not you have named parameters! The only difference is that the *meanings* "day", "month" and "year", which are part of the API in either case(!), are attached to the *positions* of the parameters. So now the *positions* of parameters are an irreducible part of the public API.

And frankly to me that's a lot worse than having the names being part of it. Names you can at least remember sometimes. Positions are fully arbitrary. Named parameters are just the API being honest about the meaning it *already* carries in its specification, instead of hiding it behind meaningless numbers.
February 08, 2020
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?

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

Why is that more useful than support for forwarding?
February 08, 2020
On 07.02.20 21:49, jmh530 wrote:
> On Friday, 7 February 2020 at 20:02:18 UTC, Walter Bright wrote:
>> [snip]
>>
>> So,
>>
>>     void foo(int a, ...);
>>
>> called with:
>>
>>     foo(b:1, 2)
>>
>> should be the equivalent of:
>>
>>     foo(2, 1)
>>
>> ?
> 
> This was on the feedback thread, but I didn't want to pollute that...

Here's my answer from the feedback thread:

I was thinking about template variadics, not sure about the C-style ones. I think your example would not match in any case, because unnamed arguments after a named argument match the next parameter, so actually you don't provide a value for 'a'. Also, the name would have to be preserved through the template instantiation.

void foo(T...)(int a, T args){ ... }

foo(b: 1, a: 2)
<=>
foo!(b: int)(2, 1);

Constructs like https://dlang.org/library/std/typecons/proxy.html should ideally not break.