Jump to page: 1 2
Thread overview
Dream Feature Regarding Default Arguments
Apr 06, 2014
Nick Sabalausky
Apr 06, 2014
Nick Sabalausky
Apr 06, 2014
Mason McGill
Apr 06, 2014
JN
Apr 06, 2014
Nick Sabalausky
Apr 06, 2014
Frustrated
Apr 07, 2014
Nick Sabalausky
Apr 07, 2014
Nordlöw
Apr 07, 2014
w0rp
Apr 07, 2014
Frustrated
Apr 07, 2014
Meta
Apr 07, 2014
Colden Cullen
Apr 07, 2014
Idan Arye
Apr 08, 2014
Byron
April 06, 2014
I realize this isn't the time for such a thing to be added to D, but I thought I'd put the idea out there, FWIW:

I find myself frequently needing to design APIs that work like this:

    func( [optionalFoo], [optionalBar] )

Typically, that's not permitted in C-style languages, including D. They only allow this:

    func( [optionalFoo, [optionalBar]] )

This restriction is necessary because, if the params take compatible types (ex: func(int,int)) and the caller only provides one, then there's no other way to tell which parameter the caller was trying to provide.

But when the params are different incompatible types, there's no ambiguity. This leads to the following awkward, noisy, hard-to-read idioms which I find myself using very frequently (I'm pretty sure I've seen it in Phobos, too):

    void func(Foo foo=defaultFoo, Bar bar=defaultBar) {...}
    void func(Bar bar) {
        func(defaultFoo, bar);
    }

or:

    void func(Foo foo, Bar bar=defaultBar) {...}
    void func(Bar bar=defaultBar) {
        func(defaultFoo, bar);
    }

Worse still, if there are other overloads, params, templates, etc, then this gets REALLY hairy, REALLY fast. It becomes very difficult to read, difficult to test, difficult to maintain, and difficult for users to grok the function's generated documentation.

Such a big mess for such a trivially simple API:

    func( [optionalFoo], [optionalBar] )

It would be *fantastic* if D recognized the disambiguation of using incompatible types and permitted this:

    interface Foo {}
    interface Bar {}
    class FooBar : Foo, Bar {}

    void func(Foo foo=someFoo, Bar bar=someBar) {...}

    func(myFoo); // Unambiguous, OK
    func(myBar); // Unambiguous, OK
    func(myFooBar); // Ambiguous, ERROR
April 06, 2014
On 4/5/2014 9:26 PM, Nick Sabalausky wrote:
>
> It would be *fantastic* if D recognized the disambiguation of using
> incompatible types and permitted this:
>
>      interface Foo {}
>      interface Bar {}
>      class FooBar : Foo, Bar {}
>
>      void func(Foo foo=someFoo, Bar bar=someBar) {...}
>
>      func(myFoo); // Unambiguous, OK
>      func(myBar); // Unambiguous, OK
>      func(myFooBar); // Ambiguous, ERROR

Actually, that last line should be:

     func(myFooBar); // Unambiguous, this is still interpreted as the first parameter (with the second parameter left as default) just as it is right now.

April 06, 2014
On Sunday, 6 April 2014 at 01:33:36 UTC, Nick Sabalausky wrote:
> On 4/5/2014 9:26 PM, Nick Sabalausky wrote:
>>
>> It would be *fantastic* if D recognized the disambiguation of using
>> incompatible types and permitted this:
>>
>>     interface Foo {}
>>     interface Bar {}
>>     class FooBar : Foo, Bar {}
>>
>>     void func(Foo foo=someFoo, Bar bar=someBar) {...}
>>
>>     func(myFoo); // Unambiguous, OK
>>     func(myBar); // Unambiguous, OK
>>     func(myFooBar); // Ambiguous, ERROR
>
> Actually, that last line should be:
>
>      func(myFooBar); // Unambiguous, this is still interpreted as the first parameter (with the second parameter left as default) just as it is right now.

I think D is actually one of the better languages around in terms of factoring this sort of thing out.  Here's an example argument parser that lets you define pairs of optional arguments: http://pastebin.com/RaNfwH6X.  It can be extended to allow n-tuples of optional arguments.

Argument parsing is encapsulated so writers only have to declare one function template, with a constraint that clearly expresses intent:

void func(Args...)(Args args)
    if (Pattern!(bool, AnyOf!(int, string)).matches!Args)
{
    alias Parser = Pattern!(bool, AnyOf!(int, string));
    auto parsedArgs = Parser.parse(tuple(args), tuple(false, 0, "0"));
    writeln(parsedArgs);
}

void main()
{
    func(true);         // true, 0, "0"
    func(true, 1);      // true, 1, "0"
    func(true, "1");    // true, 0, "1"
    func(true, 1, "1"); // true, 1, "1"
}
April 06, 2014
On Sunday, 6 April 2014 at 01:26:21 UTC, Nick Sabalausky wrote:
> Such a big mess for such a trivially simple API:
>
>     func( [optionalFoo], [optionalBar] )
>
> It would be *fantastic* if D recognized the disambiguation of using incompatible types and permitted this:
>
>     interface Foo {}
>     interface Bar {}
>     class FooBar : Foo, Bar {}
>
>     void func(Foo foo=someFoo, Bar bar=someBar) {...}
>
>     func(myFoo); // Unambiguous, OK
>     func(myBar); // Unambiguous, OK
>     func(myFooBar); // Ambiguous, ERROR

Wouldn't it be better to have named parameters like in Python or
C#? That way you could call the function like:

func(foo=myFoo) or func(bar=myBar) or func(foo=myFoo, bar=myBar)
and there would be no ambiguity.
April 06, 2014
On 4/6/2014 10:47 AM, JN wrote:
>
> Wouldn't it be better to have named parameters like in Python or
> C#? That way you could call the function like:
>
> func(foo=myFoo) or func(bar=myBar) or func(foo=myFoo, bar=myBar)
> and there would be no ambiguity.

Named parameters would be a good compliment to this (and I have always wanted named parameters in D), but even with them it would still be nice to be able have neat-n-tidy implementations of func([foo],[bar]) APIs that don't require the use of named params.

April 06, 2014
On Sunday, 6 April 2014 at 21:06:44 UTC, Nick Sabalausky wrote:
> On 4/6/2014 10:47 AM, JN wrote:
>>
>> Wouldn't it be better to have named parameters like in Python or
>> C#? That way you could call the function like:
>>
>> func(foo=myFoo) or func(bar=myBar) or func(foo=myFoo, bar=myBar)
>> and there would be no ambiguity.
>
> Named parameters would be a good compliment to this (and I have always wanted named parameters in D), but even with them it would still be nice to be able have neat-n-tidy implementations of func([foo],[bar]) APIs that don't require the use of named params.

How bout

func(,,x,,y)

or

func(default, default, x, default, default, y)?

where default is a keyword that substitutes the default value.

April 07, 2014
On Sunday, 6 April 2014 at 23:08:10 UTC, Frustrated wrote:
>
> How bout
>
> func(,,x,,y)

That isn't too bad (VB6 had it IIRC), but the caller still has to care about the order of the params they're ignoring. Ie if you have func([foo],[bar]) then you can't just pass in a one-param foo-only or bar-only without worrying about the unimportant detail of the arbitrary ordering (unlike with the overload approach).
April 07, 2014
> func(default, default, x, default, default, y)?
>
> where default is a keyword that substitutes the default value.

Reusing the keyword default here is clever :)

I like it.
April 07, 2014
On Sunday, 6 April 2014 at 14:47:28 UTC, JN wrote:
> Wouldn't it be better to have named parameters like in Python or
> C#? That way you could call the function like:
>
> func(foo=myFoo) or func(bar=myBar) or func(foo=myFoo, bar=myBar)
> and there would be no ambiguity.

Named parameters would be nice to have. I'm not sure how you would implement them in D, though.
April 07, 2014
On Monday, 7 April 2014 at 17:46:44 UTC, w0rp wrote:
> On Sunday, 6 April 2014 at 14:47:28 UTC, JN wrote:
>> Wouldn't it be better to have named parameters like in Python or
>> C#? That way you could call the function like:
>>
>> func(foo=myFoo) or func(bar=myBar) or func(foo=myFoo, bar=myBar)
>> and there would be no ambiguity.
>
> Named parameters would be nice to have. I'm not sure how you would implement them in D, though.

it would be relatively easy.

void myfunc(name = int x) { }

instead of

void myfunc(int x) { }

then

myfunc(name = 4);

or one could simply use the variable name

void myfunc(int x) { }

myfunc(x = 3);


Of course assignments may not be valid, one could use := instead.

myfunc(x := 3);



One could build a template to do it how were but it would require calling the function as a string,

e.g., template is passed the call as a string. The template gets the name of the function, looks up the parameter names, parses the arguments and generates the proper call string which is then mixed in.

e.g., Named(q{myfunc(x := 3)}); => myfunc(3);



« First   ‹ Prev
1 2