Function with default parameters

Simen kjaeraas simen.kjaras at gmail.com
Fri Sep 17 17:01:36 PDT 2010


Mariusz Gliwiński <alienballance at 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


More information about the Digitalmars-d-learn mailing list