Thread overview
Function with default parameters
Sep 17, 2010
Mariusz Gliwiński
Sep 17, 2010
Mariusz Gliwiński
Sep 18, 2010
Simen kjaeraas
Sep 18, 2010
Philippe Sigaud
Sep 18, 2010
Simen kjaeraas
Sep 18, 2010
Philippe Sigaud
Sep 18, 2010
Jacob Carlborg
September 17, 2010
I just could promise I've seen in D2 something like in scripting languages:

module test;

void main (string[] args) {
     test(b = "test");
}

void test(string a = "a", string b = "b", string c = "c") {
}

Basically picking just right parameter while other have default. But now I can't find syntax anywhere. This code didn't worked, could you refresh my memory?

Thanks,
Mariusz Gliwiński
September 17, 2010
On Fri, 17 Sep 2010 18:37:09 -0400, Mariusz Gliwiński <alienballance@gmail.com> wrote:

> I just could promise I've seen in D2 something like in scripting languages:
>
> module test;
>
> void main (string[] args) {
>       test(b = "test");
> }
>
> void test(string a = "a", string b = "b", string c = "c") {
> }
>
> Basically picking just right parameter while other have default. But now I can't find syntax anywhere. This code didn't worked, could you refresh my memory?

D parameters don't work this way.  You cannot specify a parameter by name.

There are tricks you can use, such as structs with initializers, but the result is probably not what you want.

-Steve
September 17, 2010
On 2010-09-18 00:40, Steven Schveighoffer wrote:
> On Fri, 17 Sep 2010 18:37:09 -0400, Mariusz Gliwiński
> <alienballance@gmail.com> wrote:
>> Basically picking just right parameter while other have default. But
>> now I can't find syntax anywhere. This code didn't worked, could you
>> refresh my memory?
>
> D parameters don't work this way. You cannot specify a parameter by name.
>
> There are tricks you can use, such as structs with initializers, but the
> result is probably not what you want.

No? That was different language then :(

Why it isn't allowed? Implementing that would be just about checking if all required parameters are filled and make something with parameter name / local function variable conflict. It would be nice a little nice thing...

Or maybe lack of this feature pulling programmer out from throwing into function 10 rarely used parameters? Would be a bad thing? What are limitations for parameter number? There are any?

Lastly, what's the most preferred way of adding many rarely used parameters into function? Been thinking about adding struct for them but it's probably not efficient. Been thinking about variadic solution, but that's just ugly since I hide possible solutions from programmer. I can make solution stateful in the meaning of adding parameters one by one because it's a method... I don't like this solution too. Named parameters would be great but... absent. As You probably understand adding foo(,,,,,,,,,bar,,,) isn't proper solution too :) Any hints?

Thanks,
Mariusz Gliwiński
September 18, 2010
Mariusz Gliwiński <alienballance@gmail.com> wrote:

> Why it isn't allowed? Implementing that would be just about checking if all required parameters are filled and make something with parameter name / local function variable conflict. It would be nice a little nice thing...

Many of us have lobbied for that feature. I understand that it's hard
finding the time to implement all the features we want, and finding the
right syntax (yours, for instance, conflicts with assignment).


> Or maybe lack of this feature pulling programmer out from throwing into function 10 rarely used parameters? Would be a bad thing? What are limitations for parameter number? There are any?

I know of no such limitation. There likely is one in the compiler, if not
in the language.


> Lastly, what's the most preferred way of adding many rarely used parameters into function? Been thinking about adding struct for them but it's probably not efficient. Been thinking about variadic solution, but that's just ugly since I hide possible solutions from programmer. I can make solution stateful in the meaning of adding parameters one by one because it's a method... I don't like this solution too. Named parameters would be great but... absent. As You probably understand adding foo(,,,,,,,,,bar,,,) isn't proper solution too  Any hints?

If you need to pass many parameters to a function, you should probably
think twice about what you're doing. It is often an indication that your
function is trying to do too much, and perhaps it should be an object of
some kind. Creating a struct with all those parameters as fields may
feel wrong, but it can be the correct solution. Also, method chaining
can be used to good effect in such situations:

struct Foo {
    int _param1 = 4;
    string _param2 = "Hello!";
    ref Foo parameter1( int value ) {
        _param1 = value;
        return this;
    }
    ref Foo parameter2( string value ) {
        _param2 = value;
        return this;
    }
    void opCall( float mandatoryParameter ) {
        // Do stuff
    }
}

@property Foo foo( ) {
    return Foo.init;
}

void main( ) {
    foo.parameter1( 3 ).parameter2( "ouch" )( 0.23 );

//If you want to use assignment, this also works:

    ((foo.parameter1 = 3).parameter2 = "ouch")( 0.23 );
}

One could also use templates to inspect std.typecons.Tuples and ascertain
the names of their fields, then use those as parameters:

import std.typecons;

void bar( T = Tuple!() )( int req1, string req2, T arg = T() ) {
    float optional = 2.54;
    static if ( __traits( compiles, { optional = arg.optional; } ) ) {
        optional = arg.optional;
    }
    // Do stuff
}

void main( ) {
    bar( 1, "bonk!" );
    bar( 1, "bonk!", Tuple!( float, "optional" )( 19.7 ) );
}

The main problem of this solution is its ugliness. One could, of
course, also use template parameters to specify which parameters are passed:

template baz( T... ) {
    void baz( U... )( int mandatory, U optional ) if ( U.length == T.length ) {
        string optionalValue = "a";
        foreach ( i, name; T ) {
            if ( name == "optionalValue" ) {
                optionalValue = optional[i];
            }
        }
    }
}

void main( ) {
	baz!("optionalValue")( 1, "b" );
}

A problem of this solution is that it's verbose, has little visual coupling
between parameter names and values, and does not check for unused parameters.
The verbosity and unused parameter problems could be lessened by making a
templated solution, but I'm not about to do that right now.

--
Simen
September 18, 2010
On 2010-09-18 00:37, Mariusz Gliwiński wrote:
> I just could promise I've seen in D2 something like in scripting languages:
>
> module test;
>
> void main (string[] args) {
> test(b = "test");
> }
>
> void test(string a = "a", string b = "b", string c = "c") {
> }
>
> Basically picking just right parameter while other have default. But now
> I can't find syntax anywhere. This code didn't worked, could you refresh
> my memory?
>
> Thanks,
> Mariusz Gliwiński

I have a simple implementation of named arguments here: http://dsource.org/projects/orange/browser/orange/util/Reflection.d search for "callWithNamedArguments".

-- 
/Jacob Carlborg
September 18, 2010
It seems doable to have some kind of function transformer (adaptor?) for
this.

from:

int foo(int a = 0, int b = 1, double c = 0.0, bool d = false) { return 1;}

alias namedParams!foo nfoo;

nfoo("d", true); // a = 0, b = 1, c = 0.0, d = true
nfoo("d", true, "b", 100); // a=0, b=100, c=0.0, d=true
nfoo(1, 2, "d", true);  // a=1, b=2, c=0.0, d=true

That is, it expects some values, then string/values couples.
Downside: in the above example, if foo accepts a string argument in first or
second position the "d" will be passed down as an argument...

or, using AA syntax:

nfoo(1, ["d":true],["b":100]);

Would that be palatable? Because I think it's doable.

To obtain the arguments names:

int foo(int a, int b, double c = 0.0, bool d = true) { return 1;}

template Name(alias foo) if (isCallable!foo)
{
    enum string Name = S!(foo.stringof);
}

template S(string s) // this template is just a trick because foo.stringof
directly displeases DMD
{
    enum string S = s;
}

writeln(Name!foo); // "int(int a, int b, double c = 0, bool d = true)"

So this gives me:

- the arguments names
- which ones have default values
- what is that default value

The difficulty here is correctly parsing the ( ,,,) part, without getting
desoriented by argument types that themselves use (,), like templated types.


Philippe


September 18, 2010
Philippe Sigaud <philippe.sigaud@gmail.com> wrote:

> It seems doable to have some kind of function transformer (adaptor?) for
> this.
>
> from:
>
> int foo(int a = 0, int b = 1, double c = 0.0, bool d = false) { return 1;}
>
> alias namedParams!foo nfoo;
>
> nfoo("d", true); // a = 0, b = 1, c = 0.0, d = true
> nfoo("d", true, "b", 100); // a=0, b=100, c=0.0, d=true
> nfoo(1, 2, "d", true);  // a=1, b=2, c=0.0, d=true
>
> That is, it expects some values, then string/values couples.
> Downside: in the above example, if foo accepts a string argument in first or
> second position the "d" will be passed down as an argument...
>
> or, using AA syntax:
>
> nfoo(1, ["d":true],["b":100]);
>
> Would that be palatable? Because I think it's doable.
>
> To obtain the arguments names:
>
> int foo(int a, int b, double c = 0.0, bool d = true) { return 1;}
>
> template Name(alias foo) if (isCallable!foo)
> {
>     enum string Name = S!(foo.stringof);
> }
>
> template S(string s) // this template is just a trick because foo.stringof
> directly displeases DMD
> {
>     enum string S = s;
> }
>
> writeln(Name!foo); // "int(int a, int b, double c = 0, bool d = true)"
>
> So this gives me:
>
> - the arguments names
> - which ones have default values
> - what is that default value
>
> The difficulty here is correctly parsing the ( ,,,) part, without getting
> desoriented by argument types that themselves use (,), like templated types.

My main problem with these solutions is that they're largely runtime
solutions. Not that calling a function with named parameters is very likely
to happen in an inner loop, now I think of it...	

-- 
Simen
September 18, 2010
>
>
> My main problem with these solutions is that they're largely runtime solutions. Not that calling a function with named parameters is very likely to happen in an inner loop, now I think of it...
>

I imagined the foo("b", 100, "d", true) version to be largely CT: variadic
list, testing and extracting done at CT.
As for the one accepting AAs, I don't know.

Philippe