March 23, 2013
On 2013-03-23 16:55, John Colvin wrote:

> A simple example is matplotlib.pyplot.plot
>
> There are so many possible flags and parameters that can be passed in
> order to get the exact behaviour you want, but commonly you'll only want
> a few set for each call. You don't want to have to set all the other
> preceding parameters, you just want to go e.g. plot(data, linewidth=5)

I've heard it was a big boost for C# when it got support for default arguments and named parameters. It made it a lot easier to integrate with COM.

-- 
/Jacob Carlborg
March 23, 2013
On Saturday, 23 March 2013 at 15:55:36 UTC, John Colvin wrote:
> On Saturday, 23 March 2013 at 15:00:13 UTC, bearophile wrote:
>> foobar:
>>
>>> Code that needs named parameters to be more readable is poorly designed code in the first place.
>>
>> Have you used a language where the usage of named arguments is idiomatic, like Python, Scala or Ada? They are sometimes useful even for well designed code, like functions with two arguments.
>>
>> Bye,
>> bearophile
>
> A simple example is matplotlib.pyplot.plot
>
> There are so many possible flags and parameters that can be passed in order to get the exact behaviour you want, but commonly you'll only want a few set for each call. You don't want to have to set all the other preceding parameters, you just want to go e.g. plot(data, linewidth=5)

Can't the monadic style thing do the trick ?

Named!plot.linewidth(5).call(data);

This is doable with actual D using compile time reflection.
March 24, 2013
On Saturday, 23 March 2013 at 19:56:17 UTC, deadalnix wrote:
> On Saturday, 23 March 2013 at 15:55:36 UTC, John Colvin wrote:
>> On Saturday, 23 March 2013 at 15:00:13 UTC, bearophile wrote:
>>> foobar:
>>>
>>>> Code that needs named parameters to be more readable is poorly designed code in the first place.
>>>
>>> Have you used a language where the usage of named arguments is idiomatic, like Python, Scala or Ada? They are sometimes useful even for well designed code, like functions with two arguments.
>>>
>>> Bye,
>>> bearophile
>>
>> A simple example is matplotlib.pyplot.plot
>>
>> There are so many possible flags and parameters that can be passed in order to get the exact behaviour you want, but commonly you'll only want a few set for each call. You don't want to have to set all the other preceding parameters, you just want to go e.g. plot(data, linewidth=5)
>
> Can't the monadic style thing do the trick ?
>
> Named!plot.linewidth(5).call(data);
>
> This is doable with actual D using compile time reflection.

Good point, and I'm sure we all develop our personal sense of 'code smell' based on our own past experience. I find adding lots of enums to be like doing RAII in C++: I find it a pain to have to pollute namespaces with extra enums (classes), just to get readability/safety.

To me, the builder/monadic style is clunky and harder to read. I find

plot(data, linewidth = 5)

to be clean, clear, and more concise.
March 24, 2013
I updated
https://github.com/timotheecour/dtools/blob/master/dtools/util/functional.d
to incorporate Jacob Carlborg's idea (thanks for the working+clean code! let me know if attribution is ok)

auto a=named!fun.z(3).x(4).call();
and then simplified it a bit to:

auto a=named!fun.z(3).x(4)();

It's now looking pretty close to the ideal D syntax:
auto a=fun(z:3,x:4);

Notes:
auto a=fun(z=3,x=4);
doesn't seem like a good syntax compared to 'z:3,x:4', because z=3 could be ambiguous with an expression assigning 3 to z when z is in scope.


> I find it a pain to have to pollute namespaces with extra enums (classes), just to get readability/safety.
> plot(data, linewidth = 5)
> to be clean, clear, and more concise.

I agree.

In fact, I think we should push that named syntax 'named!fun.z(3).x(4)();' in std.functional once finalized, and start using it in phobos ASAP, it makes things more self documenting.

If 'fun(z:3,x:4)' syntax later comes to D, it'd be trivial to write a tool that automatically changes the named!fun syntax in people's / phobos' source code to use the new cleaner syntax.

main benefit IMO: prevent boilerplate code like this:

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

Options options;
options.x=4;
options.z=3;
auto a=fun(options);
(or similar with param expansion: auto a=fun(options.x,options.y,options.z))


thanks for your comments!
March 24, 2013
> It's now looking pretty close to the ideal D syntax:
> auto a=fun(z:3,x:4);

The last time I tried this (maybe 2 years ago, so before std.traits.ParameterNameTuple?), I used associative arrays:

alias nfoo = named!foo; // nfoo is now a function admitting AA as arguments

auto result = nfoo(["z":"Title"], ["x":1, "y":100]);


Also, I see that at one time, you used a full string syntax:

auto result = nfoo(q{z = "Title", x = 1, y = 100}); // nfoo will parse
the input string

I rather like this one. Why did you ditch it?
March 24, 2013
On 2013-03-24 03:05, timotheecour wrote:
> I updated
> https://github.com/timotheecour/dtools/blob/master/dtools/util/functional.d
> to incorporate Jacob Carlborg's idea (thanks for the working+clean code!
> let me know if attribution is ok)

Absolutely.

> If 'fun(z:3,x:4)' syntax later comes to D, it'd be trivial to write a
> tool that automatically changes the named!fun syntax in people's /
> phobos' source code to use the new cleaner syntax.
>
> main benefit IMO: prevent boilerplate code like this:
>
> struct Options{int x; int y=1; int z=2;}
> auto fun(Options options);
>
> Options options;
> options.x=4;
> options.z=3;
> auto a=fun(options);
> (or similar with param expansion: auto
> a=fun(options.x,options.y,options.z))

What would be nice is to be able to do like this:

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

fun(y: 2, z: 45, x: 4);

Then add opDispatch to Options to soak up any varialble not found in Options:

struct Options
{
    int x;
    int y = 1;
    int z = 2;

    private Variant[string] values;

    void opDispatch (string name, T) (T value)
    {
        values[name] = Variant(value);
    }
)

fun(y: 2, foo: "asd", bar: 4.0, z: 45, x: 4);

x, y, z are mapped to the variables in Options. foo and bar are handled by opDispatch.

See my proposal for anonymous structs:

http://forum.dlang.org/thread/kfbnuc$1cro$1@digitalmars.com

-- 
/Jacob Carlborg
March 24, 2013
On 2013-03-24 09:13, Philippe Sigaud wrote:

> Also, I see that at one time, you used a full string syntax:
>
> auto result = nfoo(q{z = "Title", x = 1, y = 100}); // nfoo will parse
> the input string
>
> I rather like this one. Why did you ditch it?

That would requires compile time values, i.e. no variables.

-- 
/Jacob Carlborg
March 24, 2013
On Sun, Mar 24, 2013 at 11:15 AM, Jacob Carlborg <doob@me.com> wrote:

>> auto result = nfoo(q{z = "Title", x = 1, y = 100}); // nfoo will parse
>> the input string
>>
>> I rather like this one. Why did you ditch it?
>
> That would requires compile time values, i.e. no variables.

You're right.
March 24, 2013
On 2013-03-24 03:05, timotheecour wrote:
> I updated
> https://github.com/timotheecour/dtools/blob/master/dtools/util/functional.d
> to incorporate Jacob Carlborg's idea (thanks for the working+clean code!
> let me know if attribution is ok)

BTW, why was the constructor added to Proxy and the "dummy" argument?

-- 
/Jacob Carlborg
March 24, 2013
> BTW, why was the constructor added to Proxy and the "dummy" argument?

because I wanted to simplify syntax from 'auto
ret2=named!fun.z(3).x(4).call();' to 'auto
ret2=named!fun.z(3).x(4)();'
In doing that, I was having CT errors without it due to ambiguity
between default unnamed constructor and opCall, so I added
constructor.
Then inside the named() function i needed to return a proxy object.
Alternatives were:
return Proxy!(func, null)(); //wrong: would call opCall
return Proxy!(func, null).init; //not sure if it would incur overhead
return Proxy!(func, null)(0); //introduces dummy arg, which should be
optimized away.

If you can find a better way (that doesn't incur runtime overhead),
please do a pull request!
Also, I'm wondering about:
* how to put the unittest helper function "fun" inside main unittest block
* whether the named!fun.z(3).x(4)(); call has any overhead over
calling fun(4,2,3) directly.
* how to support templated functions (here fun is not templated)
* whether we should support this syntax:
auto ret=named!fun.z(3)(4); //this would mean named!fun.z(3).x(4)();
ie all non-optional arguments go in the opCall(..) arguments, all
optional arguments are called by name. So that would force API to
freeze names only for optional arguments, not non-optional ones, cf in
python:
fun(4,z:3)


Finally, how do I reply from my email client ? Right I'm using http://forum.dlang.org/ otherwise the message isn't delivered on the forum... Thanks!