www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - this is almost a workaround for the lack of named parameters

reply "J" <not_avail notavailable.com> writes:

void main(string[] arg) {

   // Observation: I'd like to say:
   /*
   auto r = myfunc.call("named") with { z= 2; x = -123; y = 200; }
   */

   // and have it turned into this:
   with(myfunc) { x = -123; y = 200; z = -20; }
   auto r = myfunc.call("named");

   // Q: is there some way to achieve this? Maybe a variation on 
with?

   // Is there a macro facility lurking someplace?  Or is there 
another way to do this?
   // Thanks!
   // - J
}

import std.stdio;

struct myfunc_
{
    // named keyword or named parameters
    // --the call arguments and their defaults
    int x=0;
    int y=0;
    int z=0;

    string call(string non_keyword_arg)
    {
      writefln("%s:  X %s, Y %s, Z %s", non_keyword_arg, x, y, z );
      return "yo";
    }
}
myfunc_ myfunc;
Mar 21 2013
next sibling parent reply "J" <not_avail notavailable.com> writes:
   // CORRECTION:
   // and have it turned into this:
   with(myfunc) { z =2; x = -123; y = 200; }
   auto r = myfunc.call("named");
Mar 21 2013
parent reply "J" <not_avail notavailable.com> writes:
   /*  Similarly but different (here I am instantiating a new 
struct
       before the call, rather than re-using a global single 
struct each time),
       it would be lovely and elegant to say:
   */

void main(string[] arg) {

   /* Elegant:

      auto r = myfunc() with { z= 2; x = -123; y = 200; }

   */

   // and have it lowered to:
   myfunc tmp;
   with(tmp) { z= 2; x = -123; y = 200; }
   auto r = tmp();

}

import std.stdio;

struct myfunc
{
    // named keyword or named parameters
    // --the call arguments and their defaults
    int x=0;
    int y=0;
    int z=0;

   // opCall is sweet... improves upon previous example

    string opCall(string required_positional_arg = "default pos 
arg value") {
      writefln("%s:  X %s, Y %s, Z %s", required_positional_arg, 
x, y, z );
      return "yo";
    }

}
Mar 21 2013
parent reply "J" <not_avail notavailable.com> writes:
The bigger point here is more profound: it is trivial to 
implement named parameters using structs + trivial lowerings, and 
this is no way conflicts with function overloading.

D deserves to have named parameters to functions -- it makes for 
much more legible code, and obviates the need for slow builder 
patterns.  Readable and speedable. It's win-win.
Mar 22 2013
next sibling parent reply "J" <not_avail notavailable.com> writes:
With credit for inspiration to David Medlock in this post-- 
http://forum.dlang.org/thread/d9lnrr$26q3$1 digitaldaemon.com ...

// Tongue firmly in cheek, I'd like to introduce
// the NAPAPISS principle: (with apologies to SFINAE and RAII)

// NAPAPISS = NAmed Parameters Are simply Passed in a Struct, 
Silly.

// Yes, indeed, maybe this is what happens after drinking too 
much of
// the fine wine products from the Napa valley... you start having
// wild flights of fancy of how D might surprisingly soon have
// named parameters....


import std.stdio;
import std.c.stdlib;

void main(string[] arg) {

     // this works today: but with the drawback that the
     // named params must be known at compile time...

     // Here is a named param call,
     // as compact as I could get it (see struct below for actual 
definition).

     auto a = myfunc!q{ z= 2; x = -123; y = 200 }(0)(); // calls 
opCall
     writeln("a=", a); // prints "a=yo", as returned from opCall



     // And here's the runtime version, unfortunately you have to
     // pre-declare g because otherwise it won't survive the 
scope, and
     // the return value from myfunc.opCall would become 
inaccessible.
     string g;
     with(myfunc!()(0)) {
           x=rand() % 40;
           y=x/2;
           z=y/2;
           g = call(); // as a side effect, prints 'X 7, Y 3, Z 1'
      }
      writeln("g=", g); // prints "g=yo", as returned from opCall


/*
     // The bright future: this demonstrates that
     // it would be fairly trivial to make some kind of annotation
     // like  kwarg or whaterver, to indicate that a function
     // was using this calling convention:
      kwarg string f(int a, string b) { body; }

     // so that  kwarg function definitions are lowered to:
     struct f_kw {
       int a;
       string b;
       string f() { body; }
     }

     // and calls to  kwarg functions are transformed
     // from this:
     auto r = f(a=5, b="good");

     // into this:
     f_kw tmp34;
     tmp34.a = 5;
     tmp34.b = "good";
     auto r = tmp34.f();

     // the benefit: named parameters can be used in a natural way,
     // and they need be known only at runtime.
*/
}

// how the 'works today' above examples were implemented:
struct myfunc(string init_string="")
{
    // named keyword or named parameters
    // --the call arguments and their defaults
    int x=0;
    int y=0;
    int z=0;

    this(int) {}
    string opCall() {
      mixin(init_string ~ ";");
      writefln("X %s, Y %s, Z %s", x, y, z );
      return "yo";
    }
    alias opCall call;
}


On Friday, 22 March 2013 at 09:18:33 UTC, J wrote:
 The bigger point here is more profound: it is trivial to 
 implement named parameters using structs + trivial lowerings, 
 and this is no way conflicts with function overloading.

 D deserves to have named parameters to functions -- it makes 
 for much more legible code, and obviates the need for slow 
 builder patterns.  Readable and speedable. It's win-win.
Mar 22 2013
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-03-22 11:17, J wrote:
 With credit for inspiration to David Medlock in this post--
 http://forum.dlang.org/thread/d9lnrr$26q3$1 digitaldaemon.com ...

 // Tongue firmly in cheek, I'd like to introduce
 // the NAPAPISS principle: (with apologies to SFINAE and RAII)

 // NAPAPISS = NAmed Parameters Are simply Passed in a Struct, Silly.

 // Yes, indeed, maybe this is what happens after drinking too much of
 // the fine wine products from the Napa valley... you start having
 // wild flights of fancy of how D might surprisingly soon have
 // named parameters....


 import std.stdio;
 import std.c.stdlib;

 void main(string[] arg) {

      // this works today: but with the drawback that the
      // named params must be known at compile time...

      // Here is a named param call,
      // as compact as I could get it (see struct below for actual
 definition).

      auto a = myfunc!q{ z= 2; x = -123; y = 200 }(0)(); // calls opCall
      writeln("a=", a); // prints "a=yo", as returned from opCall



      // And here's the runtime version, unfortunately you have to
      // pre-declare g because otherwise it won't survive the scope, and
      // the return value from myfunc.opCall would become inaccessible.
      string g;
      with(myfunc!()(0)) {
            x=rand() % 40;
            y=x/2;
            z=y/2;
            g = call(); // as a side effect, prints 'X 7, Y 3, Z 1'
       }
       writeln("g=", g); // prints "g=yo", as returned from opCall


 /*
      // The bright future: this demonstrates that
      // it would be fairly trivial to make some kind of annotation
      // like  kwarg or whaterver, to indicate that a function
      // was using this calling convention:
       kwarg string f(int a, string b) { body; }

      // so that  kwarg function definitions are lowered to:
      struct f_kw {
        int a;
        string b;
        string f() { body; }
      }

      // and calls to  kwarg functions are transformed
      // from this:
      auto r = f(a=5, b="good");

      // into this:
      f_kw tmp34;
      tmp34.a = 5;
      tmp34.b = "good";
      auto r = tmp34.f();

      // the benefit: named parameters can be used in a natural way,
      // and they need be known only at runtime.
 */
 }

 // how the 'works today' above examples were implemented:
 struct myfunc(string init_string="")
 {
     // named keyword or named parameters
     // --the call arguments and their defaults
     int x=0;
     int y=0;
     int z=0;

     this(int) {}
     string opCall() {
       mixin(init_string ~ ";");
       writefln("X %s, Y %s, Z %s", x, y, z );
       return "yo";
     }
     alias opCall call;
 }
Here's my proposal for anonymous structs that can be used as name parameters: http://forum.dlang.org/thread/kfbnuc$1cro$1 digitalmars.com?page=1 -- /Jacob Carlborg
Mar 22 2013
prev sibling parent reply "foobar" <foo bar.com> writes:
On Friday, 22 March 2013 at 10:17:02 UTC, J wrote:
 With credit for inspiration to David Medlock in this post-- 
 http://forum.dlang.org/thread/d9lnrr$26q3$1 digitaldaemon.com 
 ...

 // Tongue firmly in cheek, I'd like to introduce
 // the NAPAPISS principle: (with apologies to SFINAE and RAII)

 // NAPAPISS = NAmed Parameters Are simply Passed in a Struct, 
 Silly.

 // Yes, indeed, maybe this is what happens after drinking too 
 much of
 // the fine wine products from the Napa valley... you start 
 having
 // wild flights of fancy of how D might surprisingly soon have
 // named parameters....


 import std.stdio;
 import std.c.stdlib;

 void main(string[] arg) {

     // this works today: but with the drawback that the
     // named params must be known at compile time...

     // Here is a named param call,
     // as compact as I could get it (see struct below for 
 actual definition).

     auto a = myfunc!q{ z= 2; x = -123; y = 200 }(0)(); // calls 
 opCall
     writeln("a=", a); // prints "a=yo", as returned from opCall



     // And here's the runtime version, unfortunately you have to
     // pre-declare g because otherwise it won't survive the 
 scope, and
     // the return value from myfunc.opCall would become 
 inaccessible.
     string g;
     with(myfunc!()(0)) {
           x=rand() % 40;
           y=x/2;
           z=y/2;
           g = call(); // as a side effect, prints 'X 7, Y 3, Z 
 1'
      }
      writeln("g=", g); // prints "g=yo", as returned from opCall


 /*
     // The bright future: this demonstrates that
     // it would be fairly trivial to make some kind of 
 annotation
     // like  kwarg or whaterver, to indicate that a function
     // was using this calling convention:
      kwarg string f(int a, string b) { body; }

     // so that  kwarg function definitions are lowered to:
     struct f_kw {
       int a;
       string b;
       string f() { body; }
     }

     // and calls to  kwarg functions are transformed
     // from this:
     auto r = f(a=5, b="good");

     // into this:
     f_kw tmp34;
     tmp34.a = 5;
     tmp34.b = "good";
     auto r = tmp34.f();

     // the benefit: named parameters can be used in a natural 
 way,
     // and they need be known only at runtime.
 */
 }

 // how the 'works today' above examples were implemented:
 struct myfunc(string init_string="")
 {
    // named keyword or named parameters
    // --the call arguments and their defaults
    int x=0;
    int y=0;
    int z=0;

    this(int) {}
    string opCall() {
      mixin(init_string ~ ";");
      writefln("X %s, Y %s, Z %s", x, y, z );
      return "yo";
    }
    alias opCall call;
 }


 On Friday, 22 March 2013 at 09:18:33 UTC, J wrote:
 The bigger point here is more profound: it is trivial to 
 implement named parameters using structs + trivial lowerings, 
 and this is no way conflicts with function overloading.

 D deserves to have named parameters to functions -- it makes 
 for much more legible code, and obviates the need for slow 
 builder patterns.  Readable and speedable. It's win-win.
WTF? What do kwargs have to do with programming? Sounds more like a half-Klingon & half-Ferengi species to me.
Mar 22 2013
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Friday, 22 March 2013 at 20:04:14 UTC, foobar wrote:
 On Friday, 22 March 2013 at 10:17:02 UTC, J wrote:
 With credit for inspiration to David Medlock in this post-- 
 http://forum.dlang.org/thread/d9lnrr$26q3$1 digitaldaemon.com 
 ...

 // Tongue firmly in cheek, I'd like to introduce
 // the NAPAPISS principle: (with apologies to SFINAE and RAII)

 // NAPAPISS = NAmed Parameters Are simply Passed in a Struct, 
 Silly.

 // Yes, indeed, maybe this is what happens after drinking too 
 much of
 // the fine wine products from the Napa valley... you start 
 having
 // wild flights of fancy of how D might surprisingly soon have
 // named parameters....


 import std.stdio;
 import std.c.stdlib;

 void main(string[] arg) {

    // this works today: but with the drawback that the
    // named params must be known at compile time...

    // Here is a named param call,
    // as compact as I could get it (see struct below for 
 actual definition).

    auto a = myfunc!q{ z= 2; x = -123; y = 200 }(0)(); // calls 
 opCall
    writeln("a=", a); // prints "a=yo", as returned from opCall



    // And here's the runtime version, unfortunately you have to
    // pre-declare g because otherwise it won't survive the 
 scope, and
    // the return value from myfunc.opCall would become 
 inaccessible.
    string g;
    with(myfunc!()(0)) {
          x=rand() % 40;
          y=x/2;
          z=y/2;
          g = call(); // as a side effect, prints 'X 7, Y 3, Z 
 1'
     }
     writeln("g=", g); // prints "g=yo", as returned from opCall


 /*
    // The bright future: this demonstrates that
    // it would be fairly trivial to make some kind of 
 annotation
    // like  kwarg or whaterver, to indicate that a function
    // was using this calling convention:
     kwarg string f(int a, string b) { body; }

    // so that  kwarg function definitions are lowered to:
    struct f_kw {
      int a;
      string b;
      string f() { body; }
    }

    // and calls to  kwarg functions are transformed
    // from this:
    auto r = f(a=5, b="good");

    // into this:
    f_kw tmp34;
    tmp34.a = 5;
    tmp34.b = "good";
    auto r = tmp34.f();

    // the benefit: named parameters can be used in a natural 
 way,
    // and they need be known only at runtime.
 */
 }

 // how the 'works today' above examples were implemented:
 struct myfunc(string init_string="")
 {
   // named keyword or named parameters
   // --the call arguments and their defaults
   int x=0;
   int y=0;
   int z=0;

   this(int) {}
   string opCall() {
     mixin(init_string ~ ";");
     writefln("X %s, Y %s, Z %s", x, y, z );
     return "yo";
   }
   alias opCall call;
 }


 On Friday, 22 March 2013 at 09:18:33 UTC, J wrote:
 The bigger point here is more profound: it is trivial to 
 implement named parameters using structs + trivial lowerings, 
 and this is no way conflicts with function overloading.

 D deserves to have named parameters to functions -- it makes 
 for much more legible code, and obviates the need for slow 
 builder patterns.  Readable and speedable. It's win-win.
WTF? What do kwargs have to do with programming? Sounds more like a half-Klingon & half-Ferengi species to me.
kwargs = keyword arguments It's a common naming convention in python, as exemplified in matplotlib.
Mar 22 2013
parent reply "foobar" <foo bar.com> writes:
On Friday, 22 March 2013 at 21:10:27 UTC, John Colvin wrote:
 On Friday, 22 March 2013 at 20:04:14 UTC, foobar wrote:
 WTF? What do kwargs have to do with programming? Sounds more 
 like a half-Klingon & half-Ferengi species to me.
kwargs = keyword arguments It's a common naming convention in python, as exemplified in matplotlib.
That was meant more as a rhetorical question rather than a real one. Yes, I guessed the meaning by the surrounding context but nevertheless it was a major WAT while skimming the post. Also, Who the fuck cares whats common in Python? I was reading and replying on the *D* NG, was I not?
Mar 22 2013
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Friday, 22 March 2013 at 21:29:46 UTC, foobar wrote:
 On Friday, 22 March 2013 at 21:10:27 UTC, John Colvin wrote:
 On Friday, 22 March 2013 at 20:04:14 UTC, foobar wrote:
 WTF? What do kwargs have to do with programming? Sounds more 
 like a half-Klingon & half-Ferengi species to me.
kwargs = keyword arguments It's a common naming convention in python, as exemplified in matplotlib.
That was meant more as a rhetorical question rather than a real one. Yes, I guessed the meaning by the surrounding context but nevertheless it was a major WAT while skimming the post. Also, Who the fuck cares whats common in Python? I was reading and replying on the *D* NG, was I not?
Kwarg seems a reasonable name, consistent with a pre-existing convention. Please suggest a better alternative if you have one. I must admit I'm bemused by your level of aggression over what appears to be a trivial matter.
Mar 22 2013
parent reply "foobar" <foo bar.com> writes:
On Friday, 22 March 2013 at 21:41:46 UTC, John Colvin wrote:
 On Friday, 22 March 2013 at 21:29:46 UTC, foobar wrote:
 On Friday, 22 March 2013 at 21:10:27 UTC, John Colvin wrote:
 On Friday, 22 March 2013 at 20:04:14 UTC, foobar wrote:
 WTF? What do kwargs have to do with programming? Sounds more 
 like a half-Klingon & half-Ferengi species to me.
kwargs = keyword arguments It's a common naming convention in python, as exemplified in matplotlib.
That was meant more as a rhetorical question rather than a real one. Yes, I guessed the meaning by the surrounding context but nevertheless it was a major WAT while skimming the post. Also, Who the fuck cares whats common in Python? I was reading and replying on the *D* NG, was I not?
Kwarg seems a reasonable name, consistent with a pre-existing convention. Please suggest a better alternative if you have one. I must admit I'm bemused by your level of aggression over what appears to be a trivial matter.
Your read it wrong. Not aggression but rather annoyment. Also, code readability is NOT a trivial matter and people who think that it is should have their keyboard chopped off. IMHO, I think the entire feature is a code smell and glad D does not support it. Code that needs named parameters to be more readable is poorly designed code in the first place.
Mar 23 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
Mar 23 2013
next sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
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)
Mar 23 2013
next sibling parent reply Jacob Carlborg <doob me.com> writes:
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)
arguments and named parameters. It made it a lot easier to integrate with COM. -- /Jacob Carlborg
Mar 23 2013
parent "foobar" <foo bar.com> writes:
On Saturday, 23 March 2013 at 15:59:12 UTC, Jacob Carlborg wrote:
 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)
default arguments and named parameters. It made it a lot easier to integrate with COM.
AFAIK, this is only relevant or useful for COM (i.e. to support legacy, not really OO code) and is not supported (compile error?) OO).
Mar 25 2013
prev sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
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.
Mar 23 2013
parent reply "J" <notavail notavailable.com> writes:
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.
Mar 23 2013
parent reply "timotheecour" <timothee.cour2 gmail.com> writes:
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!
Mar 23 2013
next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
 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?
Mar 24 2013
parent reply Jacob Carlborg <doob me.com> writes:
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
Mar 24 2013
parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
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.
Mar 24 2013
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
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
Mar 24 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
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
Mar 24 2013
parent reply "timotheecour" <timothee.cour2 gmail.com> writes:
 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!
Mar 24 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-03-24 20:59, timotheecour wrote:
 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.
Aha, ok I see.
 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!
I'm using Thunderbird and just using "Reply to the message". -- /Jacob Carlborg
Mar 24 2013
parent reply a a <thelastmammoth gmail.com> writes:
 I'm using Thunderbird and just using "Reply to the message".
using gmail but doesn't work... (testing again via this message...) pls ignore if this succeeds!
Mar 24 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-03-24 23:53, a a wrote:

 using gmail but doesn't work... (testing again via this message...) pls
 ignore if this succeeds!
I got this. -- /Jacob Carlborg
Mar 25 2013
prev sibling parent reply "foobar" <foo bar.com> writes:
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
"idiomatic" is a relative term, tightly coupled to a specific language. Idiomatic D code for example is very different from idiomatic Haskell code. Idiomatic Python style in D would be very unidiomatic D code and vise versa. Each language has its own conventions, styles, set of distinct features, etc, etc and trying to use "language A" style while coding in "language B" is like trying to fit a square peg in a round hole. For instance, I would NOT use smalltalk naming conventions while writing say Java code. Both have very good and very consistent styles that are tightly coupled with their respective syntaxes and are very unsuitable to use in the other language. In short, if you want to discuss python features, style or specific math plotting libraries, please post to the python mailing list, not D's NG.
Mar 25 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
foobar:

 "idiomatic" is a relative term, tightly coupled to a specific 
 language. Idiomatic D code for example is very different from 
 idiomatic Haskell code.
 Idiomatic Python style in D would be very unidiomatic D code 
 and vise versa. Each language has its own conventions, styles, 
 set of distinct features, etc, etc and trying to use "language 
 A" style while coding in "language B" is like trying to fit a 
 square peg in a round hole.
 For instance, I would NOT use smalltalk naming conventions 
 while writing say Java code. Both have very good and very 
 consistent styles that are tightly coupled with their 
 respective syntaxes and are very unsuitable to use in the other 
 language.

 In short, if you want to discuss python features, style or 
 specific math plotting libraries, please post to the python 
 mailing list, not D's NG.
Imperative/OOP languages are not totally different from each other, both Python and D derive strongly from C that comes partially from Algol, and D copies several things from Python (string functions, part of the module system, part of the range design comes from itertools, and so on). So comparing languages and their features is very useful. If you have not used named arguments in languages that idiomatically use them, then it's not easy for you to see how and why they are sometimes useful and good. In Python function arguments don't have a type, so named arguments are more useful than in D. But from my experience in Python, I believe D could enjoy named arguments. Bye, bearophile
Mar 25 2013
parent "foobar" <foo bar.com> writes:
On Monday, 25 March 2013 at 13:02:49 UTC, bearophile wrote:
 foobar:

 "idiomatic" is a relative term, tightly coupled to a specific 
 language. Idiomatic D code for example is very different from 
 idiomatic Haskell code.
 Idiomatic Python style in D would be very unidiomatic D code 
 and vise versa. Each language has its own conventions, styles, 
 set of distinct features, etc, etc and trying to use "language 
 A" style while coding in "language B" is like trying to fit a 
 square peg in a round hole.
 For instance, I would NOT use smalltalk naming conventions 
 while writing say Java code. Both have very good and very 
 consistent styles that are tightly coupled with their 
 respective syntaxes and are very unsuitable to use in the 
 other language.

 In short, if you want to discuss python features, style or 
 specific math plotting libraries, please post to the python 
 mailing list, not D's NG.
Imperative/OOP languages are not totally different from each other, both Python and D derive strongly from C that comes partially from Algol, and D copies several things from Python (string functions, part of the module system, part of the range design comes from itertools, and so on). So comparing languages and their features is very useful. If you have not used named arguments in languages that idiomatically use them, then it's not easy for you to see how and why they are sometimes useful and good. In Python function arguments don't have a type, so named arguments are more useful than in D. But from my experience in Python, I believe D could enjoy named arguments. Bye, bearophile
C is a HORRIBLE language regarding naming conventions and is a *very poor choice* to learn from in this regard. Python sets very high expectations regarding "beautiful code" and IMHO fails miserably (more so because of the starting higher expectations). I admit to being spoiled by actually beautifully designed languages that are far superior in that respect. I suggest to learn Smalltalk for a language that emphasizes code readability decades before Python became cool. I find Ruby which is based on Smalltalk's semantics and spirit to be more elegant and less pretentious compared to Python.
Mar 25 2013
prev sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Friday, 22 March 2013 at 09:18:33 UTC, J wrote:
 The bigger point here is more profound: it is trivial to 
 implement named parameters using structs + trivial lowerings, 
 and this is no way conflicts with function overloading.

 D deserves to have named parameters to functions -- it makes 
 for much more legible code, and obviates the need for slow 
 builder patterns.  Readable and speedable. It's win-win.
Question for specialists of the topic : are parameter name available using compile time reflection ? Because if they are, the problem boils down to perfect forwarding issue. And it seems solvable : NamedCall!( function, "foo", fooVal, "bar", barVal); // Booya !
Mar 22 2013
parent reply "Dicebot" <m.strashun gmail.com> writes:

Mar 22 2013
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Friday, 22 March 2013 at 15:50:38 UTC, Dicebot wrote:

Seems to me like a solved problem.
Mar 22 2013
parent reply "timotheecour" <timothee.cour2 gmail.com> writes:
so i hacked up a working solution yesterday.
advantages over 
https://github.com/jacob-carlborg/mambo/blob/master/mambo/util/Reflection.d#L135:
no need to no arguments at CT (just names); allows optional and 
non optional ones; allows return value; also, mambo depends on 
tango and is hard to revive.

More later.


see:
https://github.com/timotheecour/dtools/blob/master/dtools/util/functional.d

nothing to install, just call:
rdmd --main -unittest dtools/util/functional.d


auto s=callNamed!(fun,`x,y`)(10,20);
given a function:
auto fun(int x,int y=2,double z=z_val, string z2="asdf");

Compile time errors will occur on duplicate param names, or ones 
that don't exist, or ones that are not optional and not provided 
(eg x, above)

Feel free to contribute / comment
Mar 22 2013
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Friday, 22 March 2013 at 18:48:56 UTC, timotheecour wrote:
 so i hacked up a working solution yesterday.
 advantages over 
 https://github.com/jacob-carlborg/mambo/blob/master/mambo/util/Reflection.d#L135:
 no need to no arguments at CT (just names); allows optional and 
 non optional ones; allows return value; also, mambo depends on 
 tango and is hard to revive.

 More later.


 see:
 https://github.com/timotheecour/dtools/blob/master/dtools/util/functional.d

 nothing to install, just call:
 rdmd --main -unittest dtools/util/functional.d


 auto s=callNamed!(fun,`x,y`)(10,20);
 given a function:
 auto fun(int x,int y=2,double z=z_val, string z2="asdf");

 Compile time errors will occur on duplicate param names, or 
 ones that don't exist, or ones that are not optional and not 
 provided (eg x, above)

 Feel free to contribute / comment
Don't have time to look at the code now, but it seems awesome ! Great leverage of language capabilities. Slightly different from my proposal, but I'm really not sure which interface fit best. I'm starting to think this should be : callNamed!(fun,`x`, `y`)(10,20); But I'm not sure of all the pro and cons.
Mar 22 2013
next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
22-Mar-2013 23:03, deadalnix пишет:
 On Friday, 22 March 2013 at 18:48:56 UTC, timotheecour wrote:
 so i hacked up a working solution yesterday.
 advantages over
 https://github.com/jacob-carlborg/mambo/blob/master/mambo/util/Reflection.d#L135:

 no need to no arguments at CT (just names); allows optional and non
 optional ones; allows return value; also, mambo depends on tango and
 is hard to revive.

 More later.


 see:
 https://github.com/timotheecour/dtools/blob/master/dtools/util/functional.d


 nothing to install, just call:
 rdmd --main -unittest dtools/util/functional.d


 auto s=callNamed!(fun,`x,y`)(10,20);
 given a function:
 auto fun(int x,int y=2,double z=z_val, string z2="asdf");

 Compile time errors will occur on duplicate param names, or ones that
 don't exist, or ones that are not optional and not provided (eg x, above)

 Feel free to contribute / comment
Don't have time to look at the code now, but it seems awesome ! Great leverage of language capabilities. Slightly different from my proposal, but I'm really not sure which interface fit best. I'm starting to think this should be : callNamed!(fun,`x`, `y`)(10,20);
Can opDispatch & chaining be leveraged to get the effect of: named!(fun).x(10).y(20).call(); Or maybe even simpler?
 But I'm not sure of all the pro and cons.
-- Dmitry Olshansky
Mar 22 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-03-22 21:02, Dmitry Olshansky wrote:

 Can opDispatch & chaining  be leveraged to get the effect of:
 named!(fun).x(10).y(20).call();
Here you go: http://pastebin.com/ALaXLgt3 Use that together with "callNamed" from timotheecour. -- /Jacob Carlborg
Mar 23 2013
prev sibling parent reply "J" <not_avail notavailable.com> writes:
 auto s=callNamed!(fun,`x,y`)(10,20);
Thanks, but this is a non-solution. The name must be next to the value ( x=10, y=20), so they it will scale from 2 to 7 to 17 arguments and maintain readability.
Mar 22 2013
parent reply "J" <notavail notavailable.com> writes:
On Saturday, 23 March 2013 at 05:43:22 UTC, J wrote:
 auto s=callNamed!(fun,`x,y`)(10,20);
Thanks, but this is a non-solution. The name must be next to the value ( x=10, y=20), so they it will scale from 2 to 7 to 17 arguments and maintain readability.
For a use case, compare this call reflectAndTranslate(2, 4, 5, 6, 1, 2, false, true, 15, false, true, false); Quick, without looking at the docs, what does the false after 15 do? It's very hard to tell. Compare that to: reflectAndTranslate(x=2, y=4, z=5, offset=6, alpha=1, beta=2, invert=false, twist=true, colorBrush=15, stideReduce=false, bindMatrix=true, slow=false); It's self documenting.
Mar 23 2013
parent "deadalnix" <deadalnix gmail.com> writes:
On Saturday, 23 March 2013 at 08:20:19 UTC, J wrote:
 On Saturday, 23 March 2013 at 05:43:22 UTC, J wrote:
 auto s=callNamed!(fun,`x,y`)(10,20);
Thanks, but this is a non-solution. The name must be next to the value ( x=10, y=20), so they it will scale from 2 to 7 to 17 arguments and maintain readability.
For a use case, compare this call reflectAndTranslate(2, 4, 5, 6, 1, 2, false, true, 15, false, true, false); Quick, without looking at the docs, what does the false after 15 do? It's very hard to tell. Compare that to: reflectAndTranslate(x=2, y=4, z=5, offset=6, alpha=1, beta=2, invert=false, twist=true, colorBrush=15, stideReduce=false, bindMatrix=true, slow=false); It's self documenting.
I'd argue that with or without named parameter, that code is ugly as hell. First, boolean can be replaced by enums for great benefice. Secondly, the usage of struct would also improve things quite a lot (x, y, z) is a point or a vector or something. At the end, it is about giving semantic to your code. BTW, monadic style named parameters have been proposed earlier, and I have to say this is really nice.
Mar 23 2013
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-03-21 19:35, J wrote:

Here's another workaround: 
https://github.com/jacob-carlborg/mambo/blob/master/mambo/util/Reflection.d#L135

-- 
/Jacob Carlborg
Mar 21 2013
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Jacob Carlborg:

 Here's another workaround: 
 https://github.com/jacob-carlborg/mambo/blob/master/mambo/util/Reflection.d#L135
Maybe such two links should go in one page of the D wiki about lack of named parameters workarounds. Eventually D should introduce a syntax for named arguments at the call point plus a syntax to deprecate argument names. It's not the most important thing that D currently lacks, but it's an improvement. Bye, bearophile
Mar 21 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-03-21 21:33, bearophile wrote:

 Maybe such two links should go in one page of the D wiki about lack of
 named parameters workarounds.

 Eventually D should introduce a syntax for named arguments at the call
 point plus a syntax to deprecate argument names. It's not the most
 important thing that D currently lacks, but it's an improvement.
What do you think about my suggestion for anonymous structs as named parameters? http://forum.dlang.org/thread/kfbnuc$1cro$1 digitalmars.com?page=1 -- /Jacob Carlborg
Mar 21 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Jacob Carlborg:

 What do you think about my suggestion for anonymous structs as 
 named parameters?
You show code like: void foo ({ int x, int y } point) { } foo({ y: 5, x: 3 }); D already has two kinds of tuples so I don't want a "third kind" of tuple. What I want is D to manage better the Phobos Tuple we already have, adding an unpacking syntax (http://forum.dlang.org/thread/gridjorxqlpoytuxwpsg forum.dlang.org ). (This is not supposed to solve the named arguments problem). Bye, bearophile
Mar 21 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-03-21 22:18, bearophile wrote:

 You show code like:

 void foo ({ int x, int y } point)
 {
 }

 foo({ y: 5, x: 3 });


 D already has two kinds of tuples so I don't want a "third kind" of
 tuple. What I want is D to manage better the Phobos Tuple we already
 have, adding an unpacking syntax
 (http://forum.dlang.org/thread/gridjorxqlpoytuxwpsg forum.dlang.org ).
 (This is not supposed to solve the named arguments problem).
This is not a tuple, it's an anonymous struct. -- /Jacob Carlborg
Mar 22 2013
prev sibling parent reply "J" <not_avail notavailable.com> writes:
On Thursday, 21 March 2013 at 19:59:01 UTC, Jacob Carlborg wrote:
 On 2013-03-21 19:35, J wrote:

 Here's another workaround: 
 https://github.com/jacob-carlborg/mambo/blob/master/mambo/util/Reflection.d#L135
Intriguing, Jacob! I could learn alot about reflection by studying your code. How is it installed? I installing by downloading that single file, and with a quick hack to the Reflection.d top three lines (commenting out the module and imports at the top), I tried calling it with this, no luck: import Reflection; // with module and imports commented out... import std.stdio; string my(int a, int b) { writeln(a/b); return "howdy"; } void main(string[] arg) { auto s = callWithNamedArguments(my, `a=3, b=4`); } // yields: $ ./ref.d ./ref.d(13): Error: function ref.my (int a, int b) is not callable using argument types () ./ref.d(13): Error: expected 2 function arguments, not 0
Mar 21 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-03-21 21:42, J wrote:

 Intriguing, Jacob!  I could learn alot about reflection by studying your
 code.

 How is it installed?  I installing by downloading that single file, and
 with a quick hack to the Reflection.d top three lines (commenting out
 the module and imports at the top), I tried calling it with this, no luck:



 import Reflection; // with module and imports commented out...
 import std.stdio;

 string my(int a, int b) {
    writeln(a/b);
    return "howdy";
 }

 void main(string[] arg) {

     auto s = callWithNamedArguments(my, `a=3, b=4`);
 }

 // yields:

 $ ./ref.d
 ./ref.d(13): Error: function ref.my (int a, int b) is not callable using
 argument types ()
 ./ref.d(13): Error: expected 2 function arguments, not 0
It's been quite a while since I tested that code. I'll see what I can do. -- /Jacob Carlborg
Mar 21 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-03-21 19:35, J wrote:

[snip]

I just noticed that Michel Fortin has implemented basic support for 
named parameters. I've updated his code to the latest DMD and pushed it 
to my fork:

https://github.com/jacob-carlborg/dmd/commit/e363a093040c4b14e7e814027c3e199676c82820

 From the commit message:

Add basic support for named parameters.

This will only allow to add the name of the parameter
when calling a function. It doesn't not support passing
the arguments out of order.

All credit goes to Michel Fortin.

-- 
/Jacob Carlborg
Mar 25 2013
next sibling parent reply "J" <notavail notavailable.com> writes:
On Monday, 25 March 2013 at 16:03:38 UTC, Jacob Carlborg wrote:
 On 2013-03-21 19:35, J wrote:

 [snip]

 I just noticed that Michel Fortin has implemented basic support 
 for named parameters. I've updated his code to the latest DMD 
 and pushed it to my fork:

 https://github.com/jacob-carlborg/dmd/commit/e363a093040c4b14e7e814027c3e199676c82820

 From the commit message:

 Add basic support for named parameters.

 This will only allow to add the name of the parameter
 when calling a function. It doesn't not support passing
 the arguments out of order.

 All credit goes to Michel Fortin.
+1000 Excellent!
Mar 25 2013
parent "J" <noone notlisted.notlisted.com> writes:
On Monday, 25 March 2013 at 18:11:54 UTC, J wrote:
 On Monday, 25 March 2013 at 16:03:38 UTC, Jacob Carlborg wrote:
 On 2013-03-21 19:35, J wrote:

 [snip]

 I just noticed that Michel Fortin has implemented basic 
 support for named parameters. I've updated his code to the 
 latest DMD and pushed it to my fork:

 https://github.com/jacob-carlborg/dmd/commit/e363a093040c4b14e7e814027c3e199676c82820

 From the commit message:

 Add basic support for named parameters.

 This will only allow to add the name of the parameter
 when calling a function. It doesn't not support passing
 the arguments out of order.

 All credit goes to Michel Fortin.
+1000 Excellent!
Wow. This is really nice! I added a method to Michel's nice work. You can get it in this branch. https://github.com/glycerine/dmd/tree/namedarg All the dmd test suite then passes. You can now do this: void test (double y, double z, int a, int b, int c, string d) { } void main () { test(y: 33.3, z: 44.4, a: 9999, b: 8888, 7777, // truly optional d:"Yehaw"); } I also tested the passing of named parameters through variadic templates, and there is a little work needed to make them 'named argument' aware. I added a failing test for that, if anyone wants to tackle it. It is dmd/test/compilable/namedarg_vararg.d in the branch above. $ cat namedarg_vararg.d cat namedarg_vararg.d import core.vararg; import std.stdio; void test(A...)(A a) { foreach(t; a) writeln(t); } void main () { test(x:33.3, z: 44.4, a: 9999, b: 8888, 7777, d:"Yehaw"); } $ dmd namedarg_vararg.d namedarg_vararg.d(12): Error: template namedarg_vararg.test(A...)(A a) cannot deduce template function from argument types !()(x:double,z:double,a:int,b:int,int,d:string) $ * * * Wierd and cool: Since the current version requires the exact same positions as names, it is almost like you get extra refined type safety for free. Say I have a function that takes two strings. The compiler can now help me if I mistakenly switch the two... Example: void find(string needle, string haystack) { } void main () { find(haystack: "abcdefg", needle: "def"); } dmd can now helpfully point out: namedarg_haystack.d(6): Error: function namedarg_haystack.find (string needle, string haystack) is not callable using argument types (haystack:string,needle:string) Nice. This has a different feel to it than where the compiler just 'makes it right' for you, but I still really like it. Super readable.
Mar 26 2013
prev sibling parent reply "renoX" <renozyx gmail.com> writes:
On Monday, 25 March 2013 at 16:03:38 UTC, Jacob Carlborg wrote:
[cut]
 Add basic support for named parameters.

 This will only allow to add the name of the parameter
 when calling a function. It doesn't not support passing
 the arguments out of order.

 All credit goes to Michel Fortin.
Interesting, the "doesn't not support passing the arguments out of order." can be seen either as a (temporary or not) implementation limitation OR as a feature. The things to check is how this feature would work with optional parameters.. renoX
Mar 26 2013
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-03-26 10:31, renoX wrote:

 Interesting, the "doesn't not support passing the arguments out of
 order." can be seen either as a (temporary or not) implementation
 limitation OR as a feature.
I would guess it was easier. At least the change is very small. Smaller that I would have imagined.
 The things to check is how this feature would work with optional
 parameters..
Good point. -- /Jacob Carlborg
Mar 26 2013
parent reply "J" <noname notavailable.notavailabe.com> writes:
On Tuesday, 26 March 2013 at 12:14:08 UTC, Jacob Carlborg wrote:
 On 2013-03-26 10:31, renoX wrote:

 Interesting, the "doesn't not support passing the arguments 
 out of
 order." can be seen either as a (temporary or not) 
 implementation
 limitation OR as a feature.
I would guess it was easier. At least the change is very small. Smaller that I would have imagined.
 The things to check is how this feature would work with 
 optional
 parameters..
Good point.
Tested this. Seems to work fine with optional parameters. import std.stdio; void test (int a, int b = 24, int c = 12, int d = 6, int e = 3) { writeln(a); writeln(b); writeln(c); writeln(d); writeln(e); } void main () { test(a: 1, 2, c: 9999); } // output: $ ./namedarg_defaults 1 2 9999 6 3
Mar 26 2013
parent reply Timothee Cour <thelastmammoth gmail.com> writes:
Interesting, the "doesn't not support passing the arguments out of order." can
be seen either as a (temporary or not) implementation >>limitation OR as a
feature.
Named parameters are only interesting if we can skip some optional parameters. This allows the python-like syntax of specifying only a subset of parameters; otherwise this isn't very interesting. This is used heavily in python and makes code * self-documenting * avoids DRY (don't specify unused params) * avoids boilerplate of introducing auxiliary option structs and fields to it Here are just 3 examples that hopefully will convince some that named params are useful and not ugly. ---- //inspired from python's matplotlib; many more options configurable, which are set to reasonable defaults plot(x=1,y=2,color='red',width=3); //here's another one (cf inspired by scons / waf build tools in python) compile(input=["foo.cpp"] , run=true, debug=true, ldflags="-lcurl", output_dir="build"); //other example: setting optional params in a classifier trainSVM(input=X, labels=Y, C=1000, crossValidate=true, loss=squareHingeLoss) ---- Additionally, we should be able to provide arguments out of order and check at compile time that there are no duplicates and no unexistant fields. The code i posted with support for named!plot.x(2).color("red").width(3) did that, and that wasn't hard. So hopefully it won't be easy to support as well skipping, reordering and CT checking with Michel Fortin's shiny syntax. Here are some design decisions to make: given a function void fun(int a,int b=1, int c=2); * whether to support mixing named and non-named arguments in 1 call (python does) fun(0,b=1) * whether to allow both calling conventions: fun(0,1) fun(0,b=1) * whether to allow both calling conventions: fun(0,1) fun(0,b=1) * whether to tag functions callable by named params via attribute (check is done at CT): that'll indicate clearly we want to freeze names in the API named void fun(int a,int b=1, int c=2); * alternatively to above, whether to use ':' instead of '=' in function declaration void fun(int a,int b:1, int c:2); //now it's only callable by name * whether to support skipping and reordering optional args ; I argued we need to for this to be useful enough Timothee Cour
Mar 26 2013
next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 27 March 2013 at 03:29:24 UTC, Timothee Cour wrote:
 Named parameters are only interesting if we can skip some 
 optional parameters.
 This allows the python-like syntax of specifying only a subset 
 of
 parameters; otherwise this isn't very interesting. This is used
 heavily in python and makes code
 * self-documenting
 * avoids DRY (don't specify unused params)
 * avoids boilerplate of introducing auxiliary option structs 
 and fields to it

 Here are just 3 examples that hopefully will convince some that 
 named
 params are useful and not ugly.

 ----
 //inspired from python's matplotlib; many more options 
 configurable,
 which are set to reasonable defaults
 plot(x=1,y=2,color='red',width=3);

 //here's another one (cf inspired by scons / waf build tools in 
 python)
 compile(input=["foo.cpp"] , run=true, debug=true, 
 ldflags="-lcurl",
 output_dir="build");

 //other example: setting optional params in a classifier
 trainSVM(input=X, labels=Y, C=1000, crossValidate=true, 
 loss=squareHingeLoss)
 ----
How is that any better than the monadic solution proposed in the thread and that dn't require any language addition ?
Mar 26 2013
prev sibling parent "J" <notavail notavailable.com> writes:
On Wednesday, 27 March 2013 at 03:29:24 UTC, Timothee Cour wrote:
Interesting, the "doesn't not support passing the arguments 
out of order." can be seen either as a (temporary or not) 
implementation >>limitation OR as a feature.
Named parameters are only interesting if we can skip some optional parameters.
I'd say named parameters are *more* interesting with skipping and re-ordering, but still incredibly valuable even without. Let us get them in people's hands first (and start the addiction process going...bwahahaha!) Let people experience first hand how awesome they are in a quick, doable form. (Feel free to contribute code that implements those skipping and re-ordering features...) Status update: I fixed the only known bug, and added a feature. a. Named parameters now flow into variadic template arguments without a hitch. In other words, this compiles: void test(A...)(A a) {} void main () { test(b: 33.3 c: 44.4); } b. There is an name-matching escape mechanism now. It uses _underscores. If your function looks like: void f(int a, int _b) {} then you can call it like this: f(a:1, anyLabelYouWant: 3); (Actually this was necessitated by how dmd treats variadic actual arguments; it calls them _param_0, _param_1, ..., internally. I'm still going to call this escape-mechanism a feature, though.) Here's the latest (see the named_parameters branch specifically) https://github.com/glycerine/dmd/tree/named_parameters This passes all tests. Try it out. Try and break it.
Mar 26 2013
prev sibling parent reply "J" <noname notavailable.notavailabe.com> writes:
On Tuesday, 26 March 2013 at 09:31:53 UTC, renoX wrote:
 The things to check is how this feature would work with 
 optional parameters..
Another thing to check is whether there is enough information in the object files to link across separately compiled objects. Correct me if I'm wrong, but I don't think object files include the names of struct fields, nor the names of argument parameters. You might have to do what objective-C does, which is merge the parameter names into the name of the function.
Mar 26 2013
parent "J" <noname notavailable.notavailabe.com> writes:
On Tuesday, 26 March 2013 at 20:28:39 UTC, J wrote:
 On Tuesday, 26 March 2013 at 09:31:53 UTC, renoX wrote:
 The things to check is how this feature would work with 
 optional parameters..
Another thing to check is whether there is enough information in the object files to link across separately compiled objects. Correct me if I'm wrong, but I don't think object files include the names of struct fields, nor the names of argument parameters. You might have to do what objective-C does, which is merge the parameter names into the name of the function.
Or maybe there are no link time issues. If named parameters are only ever supplying additional type-check-time information, then there would be zero impact at link time. Correct?
Mar 26 2013