www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Function with default parameters

reply =?UTF-8?B?TWFyaXVzeiBHbGl3acWEc2tp?= <alienballance gmail.com> writes:
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
Sep 17 2010
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
Sep 17 2010
parent reply =?UTF-8?B?TWFyaXVzeiBHbGl3acWEc2tp?= <alienballance gmail.com> writes:
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
Sep 17 2010
parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Mariusz Gliwi=C5=84ski <alienballance gmail.com> wrote:

 Why it isn't allowed? Implementing that would be just about checking i=
f =
 all required parameters are filled and make something with parameter  =
 name / local function variable conflict. It would be nice a little nic=
e =
 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 int=
o =
 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 no= t 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 b=
ut =
 it's probably not efficient. Been thinking about variadic solution, bu=
t =
 that's just ugly since I hide possible solutions from programmer. I ca=
n =
 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 =3D 4; string _param2 =3D "Hello!"; ref Foo parameter1( int value ) { _param1 =3D value; return this; } ref Foo parameter2( string value ) { _param2 =3D 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 =3D 3).parameter2 =3D "ouch")( 0.23 ); } One could also use templates to inspect std.typecons.Tuples and ascertai= n the names of their fields, then use those as parameters: import std.typecons; void bar( T =3D Tuple!() )( int req1, string req2, T arg =3D T() ) { float optional =3D 2.54; static if ( __traits( compiles, { optional =3D arg.optional; } ) ) = { optional =3D 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 =3D=3D = = T.length ) { string optionalValue =3D "a"; foreach ( i, name; T ) { if ( name =3D=3D "optionalValue" ) { optionalValue =3D optional[i]; } } } } void main( ) { baz!("optionalValue")( 1, "b" ); } A problem of this solution is that it's verbose, has little visual coupl= ing 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
Sep 17 2010
parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
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
Sep 18 2010
parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
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
Sep 18 2010
parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
 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
Sep 18 2010
prev sibling parent Jacob Carlborg <doob me.com> writes:
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
Sep 18 2010