Named arguments via struct initialization in functions

Idan Arye via Digitalmars-d digitalmars-d at puremagic.com
Tue Mar 8 12:32:02 PST 2016


On Sunday, 6 March 2016 at 17:35:38 UTC, Seb wrote:
> Hey all,
>
> I wanted to relive the discussion on named arguments and ping 
> for its current status.
>
> There is a bunch of examples to show how needed a unified 
> solution for this problem is, let me give you one from phobos 
> [2].
>
> ```
> // I want to allow downsizing
> iota(10).sliced!(Yes.replaceArrayWithPointer, 
> Yes.allowDownsize)(4);
> ```
>
> There is of course the alternative solution that an author 
> overloads his function to the utmost, but this results in 
> complexity and duplicated code (see e.g. redBlackTree in phobos 
> [3]).
>
> Currently the best solution AFAICT is to use a struct to pass 
> such flags, like
>
> ```
> struct Options{int x; int y=1; int z=2;}
> auto fun(Options options)
> {
>     return options.x + options.y + options.z;
> }
>
> Options options = {x: 4, z: 3};
> auto a=fun(options);
> ```
>
> There are also other workarounds as discussed in [1] (e.g. with 
> CTFE string analysis [4]).
>
> I general there two solutions to this problem
> 1) get true named parameters support in D (probably complicated)
> 2) allow struct inits in functions - e.g. fun({x: 4})
>
> For 2) Jacob Carlborg has proposed something similar three 
> years ago. In his case he proposed anonymous structs which 
> might be more generally applicable, however just created the 
> struct seems easier and allows more
> It doesn't seem that complicated to me as the compiler already 
> knows the type of the argument.
>
> Using structs is not ideal, because one can't require 
> parameters, but this can be solved by having those parameters 
> as normal ones like `sliced(4, {allowDownsize: true})` and it 
> creates some maybe unnecessary overhead.
> However it is probably the easiest solution right now.
>
> What are your thoughts on this issue?
>
> On a side note: many templated functions are also complicated 
> and experiencing this issue, so it also might be worth to think 
> about this issue too ;-)
>
> Cheers,
>
> Seb
>
> [1] 
> http://forum.dlang.org/post/pxndhoskpjxvnoacajaz@forum.dlang.org
> [2] https://github.com/DlangScience/mir/issues/18
> [3] 
> https://github.com/D-Programming-Language/phobos/pull/4041/files
> [4] 
> https://github.com/timotheecour/dtools/blob/master/dtools/util/functional.d

As far as I understand, the main two problems with named 
arguments are overloading ambiguity and the fact that argument 
names are not part of the signature. Using a struct to define the 
named arguments solves the signature problem, but the ambiguity 
problem remains - it simply gets shifted from "which overload to 
choose" to "which struct to choose".

The consensus here seems to be that ambiguous code should be 
result in compilation errors(and that it should be easy for the 
compiler to detect that the code is ambiguous!), and that if 
structs are used to declare named arguments, then solving 
overloading ambiguities should be done by constructing the struct 
explicitly. Then everyone disagree regarding how structs should 
be created explicitly with named fields.

I would like to suggest an idea that will allow solving 
ambiguities without the need for new syntax(behind the syntax for 
declaring and using named arguments), be consistent with existing 
D features, and as a bonus provide a much nicer syntax:


Make it like variadic functions!


Declaring the named arguments variadically will be done by adding 
`...` after a struct argument:

     struct Options{int x; int y=1; int z=2;}
     auto fun(Options options ...)

We'll need a syntax for specifying the arguments - but that's 
more of a matter of taste than an actual technical problem, and 
it's going to be bikeshedded over and over, so for the purpose of 
describing my idea let's pick a Ruby-style `:`(because `=` will 
break the rule of if-it-compiles-as-C-it-should-work-like-C):

     fun(x: 4, z: 3);

I've promised you to solve ambiguity, right? Well, just like 
regular variadic functions can be called with an explicit array, 
named arguments variadic functions should also be callable with 
an explicit struct:

     Options options = {x: 4, z: 3};
     fun(options);

Which brings us back to square one, right? Wrong! Because at this 
point, it should be trivial to give structs a second default 
constructor:

     this(typeof(this) that ...) {
         this = that;
     }

(actual implementation may be more efficient and 
robust(preferably a syntactic sugar for postblit), but you get 
the idea). So now structs can be constructed with named 
arguments, and ambiguities could be neatly solved with:

     fun(Options(x: 4, z: 3));



P.S: If a struct-based solution is ever implemented for named 
arguments, I do hope it'll support template inference, where a 
simple PODS(Plain Old D Struct... sorry...) is automatically 
created based on the supplied arguments' names and types(and 
order!). UDA support for that could be nice too...


More information about the Digitalmars-d mailing list