January 10, 2019
On Thursday, 10 January 2019 at 10:50:24 UTC, Atila Neves wrote:
> [snip]
>
> Fully in agreement. Now if only I write that library I've been meaning to that lets you pass parameters in any order if the types are right...

That becomes a lot more interesting when you give specific types to each function parameter.

You can also have one version of the function using basic types and then another version with the specific types and then just pass the specific stuff to the basic version. Of course with D you could generate all the stuff with specific types with a mixin...
January 10, 2019
On Thu, Jan 10, 2019 at 12:04:40PM +0000, John Colvin via Digitalmars-d wrote:
> On Thursday, 10 January 2019 at 10:50:24 UTC, Atila Neves wrote:
> > On Wednesday, 9 January 2019 at 17:46:52 UTC, H. S. Teoh wrote:
> > > [...]
> > 
> > Fully in agreement. Now if only I write that library I've been meaning to that lets you pass parameters in any order if the types are right...
> 
> And doesn't cause compile times to explode?
> 
> :)

Don't worry, this is Atila we're talking about. If he comes up with any solution, you can be sure it will not hurt his precious compile times! ;-)


T

-- 
IBM = I Blame Microsoft
January 10, 2019
> Here is the one without templates
>
>
> struct Stuff_Normal {}
> struct Stuff_Special {}
>
> struct Stuff
> {
>
>   this(Stuff_Normal _, float x, float y) { ... }
>   this(Stuff_Special _, float x, float y) { ... }
> }
>
> usage
>
>   auto val = Stuff(Stuff_Normal(), 1, 2);

Not pretty syntax but I think this is the most practical solution :)

January 10, 2019
On Thursday, 10 January 2019 at 11:40:38 UTC, evilrat wrote:
> On Thursday, 10 January 2019 at 10:50:24 UTC, Atila Neves wrote:
>> On Wednesday, 9 January 2019 at 17:46:52 UTC, H. S. Teoh wrote:
>>> On Wed, Jan 09, 2019 at 05:30:32PM +0000, Atila Neves via Digitalmars-d wrote:
>>>> [...]
>>>
>>> +1. That's what the type system is for.  Dummy arguments are NEVER a good idea unless there's a need for the API to be uniform.
>>>
>>> It also makes the calling code self-documenting without needing language support for named arguments:
>>>
>>> 	auto myPerson = Person(FirstName("John"), LastName("Doe"));
>>>
>>> rather than the opaque (and thus error-prone):
>>>
>>> 	// Bug 1234: hmm, is it first name first, or last name first?
>>> 	//auto myPerson = Person("Doe", "John");
>>> 	auto myPerson = Person("John", "Doe");
>>>
>>>
>>> T
>>
>> Fully in agreement. Now if only I write that library I've been meaning to that lets you pass parameters in any order if the types are right...
>
> For that I'd actually would prefer having a language support - named parameters, like Python/C# does...

Language support isn't needed, and since this kind of feature doesn't play well with overloading...

What's the _real_ difference between `someFunc(firstName="Alice")` and `someFunc(FirstName("Alice"))`? The former saves one character? Is that really worth the cost of language support? I have a feeling a lot of feature requests neglect that each and every one of them has a cost, and there's only enough budget for so many.

>
>    void someFunc(string firstName, string lastName, int age);
>
>    // use it
>    someFunc(age=30, firstName="John", lastName="Doe");
>
> That also solves the problem when we have some default parameters and only want to pass one of them from middle/end of the list.

This can be solved with a library, which I mentioned above I want to write. You can do this today awkwardly by using a variadic template and reflecting.


January 10, 2019
On Thursday, 10 January 2019 at 12:04:40 UTC, John Colvin wrote:
> On Thursday, 10 January 2019 at 10:50:24 UTC, Atila Neves wrote:
>> On Wednesday, 9 January 2019 at 17:46:52 UTC, H. S. Teoh wrote:
>>> [...]
>>
>> Fully in agreement. Now if only I write that library I've been meaning to that lets you pass parameters in any order if the types are right...
>
> And doesn't cause compile times to explode?
>
> :)

I'm not a wizard! ;)
January 10, 2019
On Thursday, 10 January 2019 at 13:44:52 UTC, Dru wrote:
>> Here is the one without templates
>>
>>
>> struct Stuff_Normal {}
>> struct Stuff_Special {}
>>
>> struct Stuff
>> {
>>
>>   this(Stuff_Normal _, float x, float y) { ... }
>>   this(Stuff_Special _, float x, float y) { ... }
>> }
>>
>> usage
>>
>>   auto val = Stuff(Stuff_Normal(), 1, 2);
>
> Not pretty syntax but I think this is the most practical solution :)

well, you can also make factory function or static factory method that makes tags or just alias it to enum/constant to get rid of ctor call, also since tag parameter is unused name can be omitted (though this will make it look magical for someone unfamiliar with this use case)
January 10, 2019
On Thursday, 10 January 2019 at 12:37:38 UTC, H. S. Teoh wrote:
> On Thu, Jan 10, 2019 at 12:04:40PM +0000, John Colvin via Digitalmars-d wrote:
>> On Thursday, 10 January 2019 at 10:50:24 UTC, Atila Neves wrote:
>> > On Wednesday, 9 January 2019 at 17:46:52 UTC, H. S. Teoh wrote:
>> > > [...]
>> > 
>> > Fully in agreement. Now if only I write that library I've been meaning to that lets you pass parameters in any order if the types are right...
>> 
>> And doesn't cause compile times to explode?
>> 
>> :)
>
> Don't worry, this is Atila we're talking about. If he comes up with any solution, you can be sure it will not hurt his precious compile times! ;-)


Actually, they're so bad right now anyway from a baseline of acceptability to me that nothing I add on top makes it that much worse. Currently I'm trying to work out an efficient way to interpret D to run unit tests so I don't have to pay the linker tax and just avoid compiling code whilst developing. It'll be a lot of work, though... :(
January 10, 2019
On Thursday, 10 January 2019 at 13:53:40 UTC, Atila Neves wrote:
>
> What's the _real_ difference between `someFunc(firstName="Alice")` and `someFunc(FirstName("Alice"))`? The former saves one character? Is that really worth the cost of language support? I have a feeling a lot of feature requests neglect that each and every one of them has a cost, and there's only enough budget for so many.
>
Isn't there a performance cost added when using structs like that? And the real cost is the fact that you have to create all those structs meticulously and you can only use that with functions that expect such usage. With language support, you could have named arguments for every code there exists.

Anyway, the fact that arguments are named are only a bonus, the real strength of named arguments comes with optional arguments. Look at the Builder pattern, it's pretty much a workaround for lack of named/keyword arguments.

Also, named/keyword arguments shouldn't be an issue in regards to overloading and argument order. Every language I know that has named/kw arguments allows either only keyword arguments or keywords arguments at the end of the argument list. You can do:

foo(x=10)
foo(10, 20, z=30)

but you can't do:

foo(x=10, 20)

because it'd be ambiguous.
January 10, 2019
On Thu, Jan 10, 2019 at 02:35:33PM +0000, JN via Digitalmars-d wrote:
> On Thursday, 10 January 2019 at 13:53:40 UTC, Atila Neves wrote:
> > 
> > What's the _real_ difference between `someFunc(firstName="Alice")` and `someFunc(FirstName("Alice"))`? The former saves one character? Is that really worth the cost of language support? I have a feeling a lot of feature requests neglect that each and every one of them has a cost, and there's only enough budget for so many.
> > 
> Isn't there a performance cost added when using structs like that?

I highly doubt it.  Esp. with D's structs, which are designed to be "glorified ints", i.e., they are designed precisely to be passed as though they were their constituent fields. And anyway, it's nothing an optimizer can't eliminate the cost for (if there's any to begin with).


> And the real cost is the fact that you have to create all those structs meticulously and you can only use that with functions that expect such usage.

I started some time ago to sketch a generator template that uses introspection to auto-declare such structs for a function and generate overloads that accept named parameters in any order. Didn't have the time to finish it, unfortunately. But the idea was to make it as painless as possible to use this idiom.


> With language support, you could have named arguments for every code there exists.

Good point.


> Anyway, the fact that arguments are named are only a bonus, the real strength of named arguments comes with optional arguments. Look at the Builder pattern, it's pretty much a workaround for lack of named/keyword arguments.
[...]

These days, whenever my functions start needing so many optional arguments that this becomes a problem, I just start using a struct to encapsulate them instead. I wouldn't claim it's the perfect solution, but it does pretty much have equivalent functionality: you can pass values in order (MyArgs(...)), or pass them by name (MyArgs args; args.field1 = 123;), and there can be default arguments (default field values). It does need a bit more typing, but other than that it works pretty well.

And it even supports things a language-backed named argument feature can't handle: inheriting from another Args struct ("inheriting" another function's arguments) and easy passing between a set of functions that share the same set of parameters (just pass the struct instead of 10 arguments each time).


And just to be clear, I'm not *against* adding named arguments to D. Just saying that you *can* get pretty far with what's currently there.


T

-- 
Change is inevitable, except from a vending machine.
January 10, 2019
On Thu, 10 Jan 2019 13:53:40 +0000, Atila Neves wrote:
> What's the _real_ difference between `someFunc(firstName="Alice")` and
> `someFunc(FirstName("Alice"))`?
> The former saves one character?

It means you don't need to declare a new struct for every function parameter.

Even if you are willing to declare a new struct for every function parameter, it means you don't have to do the work of either creating a unique name for each one (which would be annoying to users) or manually garbage collecting the structs as your code evolves (in case a parameter struct is used by multiple functions).

Even if you're willing to do the work of declaring a new struct for each paramater, using short names, and manually garbage collecting them, language-provided named parameters mean that your end users don't need to worry about name collisions between two modules using struct wrappers as named parameters.

Even if you're willing to do the work of declaring a new struct for each parameter, with short names and manually maintaining a minimal set of parameter structs, and you're willing to make your code's consumers deal with naming conflicts, you still don't get reorderable parameters. For that, you need to turn a function into a wrapper template that accepts parameters in any order and forwards them to an implementation function in a fixed order. This makes it difficult to take the address of the function.

So, no, just using wrapper structs is not a serious alternative.