www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - std.bind documentation sucks hard

reply Georg Wrede <georg.wrede iki.fi> writes:
At first sight I thought I had become stupid. Reading the page once 
through left me with absolutely no notion on how or to what one should 
or could use bind. (And that coming from someone who actually has 
studied the STL hard (albeit 10 years ago)). I can only imagine how much 
the average D-newcomer gets out of the page.

First of all, the function bind itself is impossible to find simply by 
scanning the page. It also isn't in the Jump List at the top. Turns out 
it is hidden behind a scary line starting with typeof(new 
BoundFunc...)... stuff. (Yes, I understand it has to be there, but the 
word bind itself *has* to be "findable" by eyeballing the page down from 
the top. So put the word bind, e.g. in a mini-heading or whatever right 
before that line!)

There are no examples. Yes, there are commands in example-style boxes, 
but they aren't examples, since all we have is the bare command invocation.


An example (heh, even this post has one) of what I mean:

- bind(&foo, _0, _1) // will yield a delegate accepting two parameters
- bind(&foo, _1, _0) // will yield a delegate accepting two parameters
- bind(&bar, _0, _1, _2, _0) // will yield a delegate accepting three 
parameters

What does this tell the _new_ reader??

Another example is "const DynArg!(2) _2;" What do I use it for, and 
where. And how do I use it?


One would also expect that at the start of the page there is some text 
explaining the concept itself, where one should use bind, and for what 
benefit.

The fact that nobody has yet pointed out the blatant typo in the "long" 
"example" that I pasted above, only serves to show that most readers try 
to read and understand the page, and give up. And the page has been 
there for over 2 years.


It is not impossible to write good D doc pages, for example std.signals 
does a much better job. Or std.getopt.

And before any smarta** says well, georg, why don't you fix it, I have 
to remind that currently I hardly have the time to read these NGs. But 
even then, for every few hours of reading, I at least try to give a 
meaningful contribution in exchange.

Another smarta** might say that "it says References: boost" so read 
that. Well, one could say this about every single doc page on the site.

Anyhow, if Tomasz Stachowiak (whom I'm not attacking with this post!) is 
unavailable, then I wish somebody who actually uses bind, could submit a 
better version. Even a little improvement would be most welcome.


PS: with the newest developments in D2, bind is suddenly becoming an 
essential part of the new kind of D programming that is currently 
becoming possible!
Feb 22 2009
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Georg Wrede wrote:
 At first sight I thought I had become stupid. Reading the page once 
 through left me with absolutely no notion on how or to what one should 
 or could use bind. (And that coming from someone who actually has 
 studied the STL hard (albeit 10 years ago)). I can only imagine how much 
 the average D-newcomer gets out of the page.

 PS: with the newest developments in D2, bind is suddenly becoming an 
 essential part of the new kind of D programming that is currently 
 becoming possible!

Yah, I agree, std.bind is terribly outdated. Recent progress of D makes std.bind look like a curious silex tool. It's due for a complete rewrite. I don't have much time for that at the moment, but let's reframe this as an opportunity. Several people offered to tender their help to Phobos. Are there any takers for a new std.bind design? To avoid wasting work, let's discuss an interface first before doing any implementation. I have something in mind, but I don't want to bias anyone. So, I'm renaming this thread and launching a design contest for the new std.bind. First step: how should the interface look like? Andrei
Feb 22 2009
prev sibling next sibling parent Tom S <h3r3tic remove.mat.uni.torun.pl> writes:
Georg Wrede wrote:
 Another smarta** might say that "it says References: boost" so read 
 that. Well, one could say this about every single doc page on the site.

Well, I'll be that smarta** then. I've mostly implemented Bind for fun and I hate writing docs. I'm not sure if I actually use it in more than two(?) places in all of my projects and there was very little interest in it except the Phobos inclusion. Thus spending a few days writing docs that are already there (see the smarta** reference) was the last thing I wanted to do.
 Anyhow, if Tomasz Stachowiak (whom I'm not attacking with this post!) is 
 unavailable, then I wish somebody who actually uses bind, could submit a 
 better version. Even a little improvement would be most welcome.
 
 
 PS: with the newest developments in D2, bind is suddenly becoming an 
 essential part of the new kind of D programming that is currently 
 becoming possible!

I'm not even sure what kind of improvements it needs except the docs since I don't really use it myself and I'm stuck with D1 anyway... -- Tomasz Stachowiak http://h3.team0xf.com/ h3/h3r3tic on #D freenode
Feb 22 2009
prev sibling parent reply downs <default_357-line yahoo.de> writes:
Let me say first that I don't use std.bind myself, but tools.base:fix fills
essentially the same need - creating full closures from dynamic ones.

Say you have a function that takes a number and returns a delegate that does
something with that number.

void delegate() test(int i) { return { return i + 2; }; }

In 2.0 this will ......................

Oh.

Nevermind. I don't know what to use bind for after all :)

In fact, I suspect it's essentially useless in 2.0. Creating full closures was
my only use case :)
Feb 22 2009
next sibling parent grauzone <none example.net> writes:
A great example of how to get rid of weird, obfuscating template hacks 
by introducing simple and powerful language features.

I'm not sure if this makes it worth to switch to D2.0, though.
Feb 23 2009
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
downs Wrote:

 Let me say first that I don't use std.bind myself, but tools.base:fix fills
essentially the same need - creating full closures from dynamic ones.
 
 Say you have a function that takes a number and returns a delegate that does
something with that number.
 
 void delegate() test(int i) { return { return i + 2; }; }
 
 In 2.0 this will ......................
 
 Oh.
 
 Nevermind. I don't know what to use bind for after all :)
 
 In fact, I suspect it's essentially useless in 2.0. Creating full closures was
my only use case :)

I look at bind as the difference between by reference and by value semantics. When using scope delegates (or delegates that could be scope delegates), this difference rarely matters. When passing data between threads, the need to pass by value becomes more important. "By value" may even require a deep copy. Even though I can see uses for some kind of bind functionality in D2, I need to see where all this "shared" object stuff goes before I know what/if a D2 bind library should do.
Feb 23 2009
parent reply Lars Kyllingstad <public kyllingen.NOSPAMnet> writes:
Jason House wrote:
 downs Wrote:
 
 Let me say first that I don't use std.bind myself, but tools.base:fix fills
essentially the same need - creating full closures from dynamic ones.

 Say you have a function that takes a number and returns a delegate that does
something with that number.

 void delegate() test(int i) { return { return i + 2; }; }

 In 2.0 this will ......................

 Oh.

 Nevermind. I don't know what to use bind for after all :)

 In fact, I suspect it's essentially useless in 2.0. Creating full closures was
my only use case :)

I look at bind as the difference between by reference and by value semantics. When using scope delegates (or delegates that could be scope delegates), this difference rarely matters. When passing data between threads, the need to pass by value becomes more important. "By value" may even require a deep copy. Even though I can see uses for some kind of bind functionality in D2, I need to see where all this "shared" object stuff goes before I know what/if a D2 bind library should do.

I've always thought currying was the main point of std.bind. If I'm not mistaken, currying is commonly a built-in feature of functional programming languages, so if anything, std.bind could become more useful/important in D2 than in D1. I agree that the std.bind API could and should be improved. -Lars
Feb 24 2009
parent reply Yigal Chripun <yigal100 gmail.com> writes:
Lars Kyllingstad wrote:
 Jason House wrote:
 downs Wrote:

 Let me say first that I don't use std.bind myself, but tools.base:fix
 fills essentially the same need - creating full closures from dynamic
 ones.

 Say you have a function that takes a number and returns a delegate
 that does something with that number.

 void delegate() test(int i) { return { return i + 2; }; }

 In 2.0 this will ......................

 Oh.

 Nevermind. I don't know what to use bind for after all :)

 In fact, I suspect it's essentially useless in 2.0. Creating full
 closures was my only use case :)

I look at bind as the difference between by reference and by value semantics. When using scope delegates (or delegates that could be scope delegates), this difference rarely matters. When passing data between threads, the need to pass by value becomes more important. "By value" may even require a deep copy. Even though I can see uses for some kind of bind functionality in D2, I need to see where all this "shared" object stuff goes before I know what/if a D2 bind library should do.

I've always thought currying was the main point of std.bind. If I'm not mistaken, currying is commonly a built-in feature of functional programming languages, so if anything, std.bind could become more useful/important in D2 than in D1. I agree that the std.bind API could and should be improved. -Lars

you don't need bind for currying, it's even possible to do this in C: int foo(int a, int b) { ... } int bar(int a) { return foo(a, _value); } // curry with some _value Other languages provide useful syntax sugar for currying: auto bar2 = foo(_, 500); bar2 here will be a delegate that will do the the same as the above bar.
Feb 24 2009
parent reply downs <default_357-line yahoo.de> writes:
Yigal Chripun wrote:
 Lars Kyllingstad wrote:
 I've always thought currying was the main point of std.bind. If I'm not
 mistaken, currying is commonly a built-in feature of functional
 programming languages, so if anything, std.bind could become more
 useful/important in D2 than in D1.

 I agree that the std.bind API could and should be improved.

 -Lars

you don't need bind for currying, it's even possible to do this in C: int foo(int a, int b) { ... } int bar(int a) { return foo(a, _value); } // curry with some _value Other languages provide useful syntax sugar for currying: auto bar2 = foo(_, 500); bar2 here will be a delegate that will do the the same as the above bar.

Just for comparison' sake: auto dg = &foo /rfix/ somevar; // 1.0, tools auto dg = _bind(&foo, _1, somevar); // 1.0, std.bind auto dg = (int a) { return foo(a, somevar); }; // 2.0, literal
Feb 24 2009
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
downs:

 auto dg = &foo /rfix/ somevar;			// 1.0, tools
 auto dg = _bind(&foo, _1, somevar);		// 1.0, std.bind
 auto dg = (int a) { return foo(a, somevar); };	// 2.0, literal

I like none of those :-) (but the 2.0 literal is a bit better). Bye, bearophile
Feb 24 2009
prev sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
downs wrote:
 Yigal Chripun wrote:
 Lars Kyllingstad wrote:
 I've always thought currying was the main point of std.bind. If I'm not
 mistaken, currying is commonly a built-in feature of functional
 programming languages, so if anything, std.bind could become more
 useful/important in D2 than in D1.

 I agree that the std.bind API could and should be improved.

 -Lars

int foo(int a, int b) { ... } int bar(int a) { return foo(a, _value); } // curry with some _value Other languages provide useful syntax sugar for currying: auto bar2 = foo(_, 500); bar2 here will be a delegate that will do the the same as the above bar.

Just for comparison' sake: auto dg =&foo /rfix/ somevar; // 1.0, tools auto dg = _bind(&foo, _1, somevar); // 1.0, std.bind auto dg = (int a) { return foo(a, somevar); }; // 2.0, literal

So does that mean you like the above suggestion? after all, it's shorter and clearer than all the other alternatives.. ;)
Feb 24 2009
parent reply Lars Kyllingstad <public kyllingen.NOSPAMnet> writes:
Yigal Chripun wrote:
 downs wrote:
 Yigal Chripun wrote:
 Lars Kyllingstad wrote:
 I've always thought currying was the main point of std.bind. If I'm not
 mistaken, currying is commonly a built-in feature of functional
 programming languages, so if anything, std.bind could become more
 useful/important in D2 than in D1.

 I agree that the std.bind API could and should be improved.

 -Lars

int foo(int a, int b) { ... } int bar(int a) { return foo(a, _value); } // curry with some _value Other languages provide useful syntax sugar for currying: auto bar2 = foo(_, 500); bar2 here will be a delegate that will do the the same as the above bar.

Just for comparison' sake: auto dg =&foo /rfix/ somevar; // 1.0, tools auto dg = _bind(&foo, _1, somevar); // 1.0, std.bind auto dg = (int a) { return foo(a, somevar); }; // 2.0, literal

So does that mean you like the above suggestion? after all, it's shorter and clearer than all the other alternatives.. ;)

I for one like it, and would very much like to see such a syntax in D2. Also, I'd have it work with either of a function's arguments, not only the leading or trailing ones: int foo(int a, int b, int c, int d) {...} auto bar1 = foo(_, b, c, d); auto bar2 = foo(a, b, c, _); auto bar3 = foo(_, b, _, d); assert (is (typeof(bar3) == int delegate(int, int))); In its simplest form, it would just be syntactic sugar for the delegate literal. But I'm curious: If foo is a pure function, couldn't the compiler perform some extra optimization here? -Lars
Feb 24 2009
next sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
Lars Kyllingstad wrote:
 Yigal Chripun wrote:
 downs wrote:
 Yigal Chripun wrote:
 Lars Kyllingstad wrote:
 I've always thought currying was the main point of std.bind. If I'm
 not
 mistaken, currying is commonly a built-in feature of functional
 programming languages, so if anything, std.bind could become more
 useful/important in D2 than in D1.

 I agree that the std.bind API could and should be improved.

 -Lars

int foo(int a, int b) { ... } int bar(int a) { return foo(a, _value); } // curry with some _value Other languages provide useful syntax sugar for currying: auto bar2 = foo(_, 500); bar2 here will be a delegate that will do the the same as the above bar.

Just for comparison' sake: auto dg =&foo /rfix/ somevar; // 1.0, tools auto dg = _bind(&foo, _1, somevar); // 1.0, std.bind auto dg = (int a) { return foo(a, somevar); }; // 2.0, literal

So does that mean you like the above suggestion? after all, it's shorter and clearer than all the other alternatives.. ;)

I for one like it, and would very much like to see such a syntax in D2. Also, I'd have it work with either of a function's arguments, not only the leading or trailing ones:

 int foo(int a, int b, int c, int d) {...}
 auto bar1 = foo(_, b, c, d);
 auto bar2 = foo(a, b, c, _);
 auto bar3 = foo(_, b, _, d);

 assert (is (typeof(bar3) == int delegate(int, int)));

no such restriction was intended. but that's good that you made this clear. the only restriction here is re-ordering: bar3(A, C) will always call foo(A, b, C, d) but since it's just syntax sugar and will be expanded by the language to the delegate literal this is not a big deal - the user can always re-order arguments by using the delegate literal syntax directly: auto reordered_bar3 = (int C, int A) { return foo(A, b, C, d); };
 In its simplest form, it would just be syntactic sugar for the delegate
 literal. But I'm curious: If foo is a pure function, couldn't the
 compiler perform some extra optimization here?

 -Lars

what kind of optimizations you had in mind? b & d in bar3 above can be specified at run-time so you can't avoid the intermidiate delegate, I think.
Feb 24 2009
parent reply Lars Kyllingstad <public kyllingen.NOSPAMnet> writes:
Yigal Chripun wrote:
 Lars Kyllingstad wrote:
 Yigal Chripun wrote:
 downs wrote:
 Yigal Chripun wrote:
 Lars Kyllingstad wrote:
 I've always thought currying was the main point of std.bind. If I'm
 not
 mistaken, currying is commonly a built-in feature of functional
 programming languages, so if anything, std.bind could become more
 useful/important in D2 than in D1.

 I agree that the std.bind API could and should be improved.

 -Lars

int foo(int a, int b) { ... } int bar(int a) { return foo(a, _value); } // curry with some _value Other languages provide useful syntax sugar for currying: auto bar2 = foo(_, 500); bar2 here will be a delegate that will do the the same as the above bar.

Just for comparison' sake: auto dg =&foo /rfix/ somevar; // 1.0, tools auto dg = _bind(&foo, _1, somevar); // 1.0, std.bind auto dg = (int a) { return foo(a, somevar); }; // 2.0, literal

So does that mean you like the above suggestion? after all, it's shorter and clearer than all the other alternatives.. ;)

I for one like it, and would very much like to see such a syntax in D2. Also, I'd have it work with either of a function's arguments, not only the leading or trailing ones:

 int foo(int a, int b, int c, int d) {...}
 auto bar1 = foo(_, b, c, d);
 auto bar2 = foo(a, b, c, _);
 auto bar3 = foo(_, b, _, d);

 assert (is (typeof(bar3) == int delegate(int, int)));

no such restriction was intended. but that's good that you made this clear. the only restriction here is re-ordering: bar3(A, C) will always call foo(A, b, C, d) but since it's just syntax sugar and will be expanded by the language to the delegate literal this is not a big deal - the user can always re-order arguments by using the delegate literal syntax directly: auto reordered_bar3 = (int C, int A) { return foo(A, b, C, d); };
 In its simplest form, it would just be syntactic sugar for the delegate
 literal. But I'm curious: If foo is a pure function, couldn't the
 compiler perform some extra optimization here?

 -Lars

what kind of optimizations you had in mind? b & d in bar3 above can be specified at run-time so you can't avoid the intermidiate delegate, I think.

I'm on thin ice here, I know, but consider the following simple example: pure real foo(real a, real b, real c) { auto tmp = sqrt(b + c); return tmp + a; } auto bar = foo(_, x, y); Since bar now carries with it the last two arguments, it should in principle only have to calculate the square root once, i.e. the last line above would be equivalent to something like struct Bar { auto tmp; pure real bar(real a) { return tmp + a; } } auto bar = &Bar(sqrt(x+y)).bar; -Lars
Feb 24 2009
next sibling parent Lars Kyllingstad <public kyllingen.NOSPAMnet> writes:
Lars Kyllingstad wrote:
   struct Bar
   {
     auto tmp;
 
     pure real bar(real a) { return tmp + a; }
   }

Correction: bar shouldn't be marked as pure here, or I guess it wouldn't have access to tmp. But you get my point: It should be possible to factor out the calculations that only involve the curryed arguments, and only perform them once. -Lars
Feb 24 2009
prev sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Lars Kyllingstad wrote:
 
 I'm on thin ice here, I know, but consider the following simple example:
 
   pure real foo(real a, real b, real c)
   {
     auto tmp = sqrt(b + c);
     return tmp + a;
   }
 
   auto bar = foo(_, x, y);
 
 Since bar now carries with it the last two arguments, it should in
 principle only have to calculate the square root once, i.e. the last
 line above would be equivalent to something like
 
   struct Bar
   {
     auto tmp;
 
     pure real bar(real a) { return tmp + a; }
   }
 
   auto bar = &Bar(sqrt(x+y)).bar;
 
 
 -Lars

There was a proposal made by Walter (or possibly Andrei) involving partial specialisation. pure real foo(real a, static real b, static real c) { return a + sqrt(b + c); } void main() { auto x = foo(1, 2, 3); } Would automagically become: pure real foo_2_3(real a) { return a + (value of sqrt(b+c), assuming sqrt was CTFE-enabled); } void main() { auto x = foo_2_3(1); } Still waiting for it, though :) -- Daniel
Feb 24 2009
parent bearophile <bearophileHUGS lycos.com> writes:
Daniel Keep:
 There was a proposal made by Walter (or possibly Andrei) involving
 partial specialisation.

...or by me :-) Bye, bearophile
Feb 24 2009
prev sibling next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Lars Kyllingstad wrote:
 [snip]
 
 I for one like it, and would very much like to see such a syntax in D2.
 Also, I'd have it work with either of a function's arguments, not only
 the leading or trailing ones:
 
   int foo(int a, int b, int c, int d) {...}
   auto bar1 = foo(_, b, c, d);
   auto bar2 = foo(a, b, c, _);
   auto bar3 = foo(_, b, _, d);
 
   assert (is (typeof(bar3) == int delegate(int, int)));
 
 In its simplest form, it would just be syntactic sugar for the delegate
 literal. But I'm curious: If foo is a pure function, couldn't the
 compiler perform some extra optimization here?
 
 -Lars

auto a = b(_, c(_, x), _); What are the types of a, b and c? What if b has multiple overloads or is templated? Context-dependant grammar (let alone context-dependant single character symbols): just say "no". -- Daniel
Feb 24 2009
parent reply Lars Kyllingstad <public kyllingen.NOSPAMnet> writes:
Daniel Keep wrote:
 
 Lars Kyllingstad wrote:
 [snip]

 I for one like it, and would very much like to see such a syntax in D2.
 Also, I'd have it work with either of a function's arguments, not only
 the leading or trailing ones:

   int foo(int a, int b, int c, int d) {...}
   auto bar1 = foo(_, b, c, d);
   auto bar2 = foo(a, b, c, _);
   auto bar3 = foo(_, b, _, d);

   assert (is (typeof(bar3) == int delegate(int, int)));

 In its simplest form, it would just be syntactic sugar for the delegate
 literal. But I'm curious: If foo is a pure function, couldn't the
 compiler perform some extra optimization here?

 -Lars

auto a = b(_, c(_, x), _); What are the types of a, b and c? What if b has multiple overloads or is templated? Context-dependant grammar (let alone context-dependant single character symbols): just say "no". -- Daniel

Good point. How about this alternative syntax, then: auto bar3 = foo(int, b, int, d); Will this also cause problems? -Lars
Feb 24 2009
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Lars Kyllingstad wrote:
 Daniel Keep wrote:
 Lars Kyllingstad wrote:
 [snip]

 I for one like it, and would very much like to see such a syntax in D2.
 Also, I'd have it work with either of a function's arguments, not only
 the leading or trailing ones:

   int foo(int a, int b, int c, int d) {...}
   auto bar1 = foo(_, b, c, d);
   auto bar2 = foo(a, b, c, _);
   auto bar3 = foo(_, b, _, d);

   assert (is (typeof(bar3) == int delegate(int, int)));

 In its simplest form, it would just be syntactic sugar for the delegate
 literal. But I'm curious: If foo is a pure function, couldn't the
 compiler perform some extra optimization here?

 -Lars

auto a = b(_, c(_, x), _); What are the types of a, b and c? What if b has multiple overloads or is templated? Context-dependant grammar (let alone context-dependant single character symbols): just say "no". -- Daniel

Good point. How about this alternative syntax, then: auto bar3 = foo(int, b, int, d); Will this also cause problems? -Lars

This doesn't address the problem of what, exactly, the context of the curried arguments is. What's more, you're putting a type where an expression is expected; I don't see how you get "currying" from "repeating an argument type." The problem I have with these suggestions are that you're basically arguing for an incredibly inflexible, context-dependant, completely unintuitive syntax for something you already have working syntax for. I just don't see the point. -- Daniel
Feb 24 2009
next sibling parent Yigal Chripun <yigal100 gmail.com> writes:
Daniel Keep wrote:
 auto a = b(_, c(_, x), _);

 What are the types of a, b and c?  What if b has multiple overloads or
 is templated?

 Context-dependant grammar (let alone context-dependant single character
 symbols): just say "no".

    -- Daniel

auto bar3 = foo(int, b, int, d); Will this also cause problems? -Lars

This doesn't address the problem of what, exactly, the context of the curried arguments is. What's more, you're putting a type where an expression is expected; I don't see how you get "currying" from "repeating an argument type." The problem I have with these suggestions are that you're basically arguing for an incredibly inflexible, context-dependant, completely unintuitive syntax for something you already have working syntax for. I just don't see the point. -- Daniel

given the following functions: int foo(int a, int b) {..} int bar(int x, int delegate(int) dg, int z) {..} here's the example you gave above in current D2: (not tested) auto temp = int(int a) { return foo(a, somevar); }; auto dg = int(int a, int c) { return bar(a, temp, c); }; or you can do it in one go: auto dg = int(int a, int c) { return bar(a, (int x){ return foo(x, somevar); }, c); }; surely using instead the following is much clearer: auto dg = bar(_, foo(_, somevar), _); all it does is generate the delegates for you. what do you mean by "the context of the curried arguments"? regarding your point on context-dependency: that is a good point indeed and can be solved by either using Lars' alternative syntax or by making ambiguities compile time errors. given the following functions: void foo(int x, int y) { ... } void foo(float x, int y) { ... } here's what happens: auto dg = foo(_, 0); // compile time error - ambiguity void delegate(int) dg = foo(_, 0); // select first overload void delegate(float) dg = foo(_, 0); // select second overload this is similar to &foo only that if there are overloads of foo: auto dg = &foo; // this IMHO shouldn't compile IIRC, the current behavior is to use the first foo. with your example, the compiler knows the signature of bar and can choose the correct overload of foo based on its type. if there's more than one overload of bar than the programmer needs to specify the type of bar to disambiguate.
Feb 24 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Daniel Keep wrote:
 The problem I have with these suggestions are that you're basically
 arguing for an incredibly inflexible, context-dependant, completely
 unintuitive syntax for something you already have working syntax for.  I
 just don't see the point.

I'd agree that generally there's a strong bias in this group for adding to the language. Every itsy-bitsy issue comes around, there are a dozen cute syntaxes invented for it right on the spot. And then once every few months, there's the inevitable huge thread "Where did my simple language go???" :o) Currying/binding can be done easily with a library, and the implementation is so simple there's no need for a separate file dedicated to it. The one interesting case is currying a function passed by alias. In that case there's no indirect call, just a little struct created that contains the curried state: int plus(int x, int y} { return x + y; } auto plus5 = curry!(plus)(5); assert(plus5(10) == 15); typeof(plus5) will be a little struct that may be cumbersome to pass around, in which case you do want to take the toll of the indirect call by writing: auto plus5 = makeDelegate(curry!(plus)(5)); assert(is(typeof(plus5) == int delegate(int)); assert(plus5(10) == 15); This stuff belongs to std.functional. I plan to eliminate std.bind and put currying and binding in std.functional. What do people think? Andrei
Feb 24 2009
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Andrei Alexandrescu wrote:
 Daniel Keep wrote:
 The problem I have with these suggestions are that you're basically
 arguing for an incredibly inflexible, context-dependant, completely
 unintuitive syntax for something you already have working syntax for.  I
 just don't see the point.

I'd agree that generally there's a strong bias in this group for adding to the language. Every itsy-bitsy issue comes around, there are a dozen cute syntaxes invented for it right on the spot. And then once every few months, there's the inevitable huge thread "Where did my simple language go???" :o) Currying/binding can be done easily with a library, and the implementation is so simple there's no need for a separate file dedicated to it. The one interesting case is currying a function passed by alias. In that case there's no indirect call, just a little struct created that contains the curried state: int plus(int x, int y} { return x + y; } auto plus5 = curry!(plus)(5); assert(plus5(10) == 15); typeof(plus5) will be a little struct that may be cumbersome to pass around, in which case you do want to take the toll of the indirect call by writing: auto plus5 = makeDelegate(curry!(plus)(5)); assert(is(typeof(plus5) == int delegate(int)); assert(plus5(10) == 15); This stuff belongs to std.functional. I plan to eliminate std.bind and put currying and binding in std.functional. What do people think?

How do you curry on the second argument?
Feb 24 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Ary Borenszweig wrote:
 Andrei Alexandrescu wrote:
 Daniel Keep wrote:
 The problem I have with these suggestions are that you're basically
 arguing for an incredibly inflexible, context-dependant, completely
 unintuitive syntax for something you already have working syntax for.  I
 just don't see the point.

I'd agree that generally there's a strong bias in this group for adding to the language. Every itsy-bitsy issue comes around, there are a dozen cute syntaxes invented for it right on the spot. And then once every few months, there's the inevitable huge thread "Where did my simple language go???" :o) Currying/binding can be done easily with a library, and the implementation is so simple there's no need for a separate file dedicated to it. The one interesting case is currying a function passed by alias. In that case there's no indirect call, just a little struct created that contains the curried state: int plus(int x, int y} { return x + y; } auto plus5 = curry!(plus)(5); assert(plus5(10) == 15); typeof(plus5) will be a little struct that may be cumbersome to pass around, in which case you do want to take the toll of the indirect call by writing: auto plus5 = makeDelegate(curry!(plus)(5)); assert(is(typeof(plus5) == int delegate(int)); assert(plus5(10) == 15); This stuff belongs to std.functional. I plan to eliminate std.bind and put currying and binding in std.functional. What do people think?

How do you curry on the second argument?

That's not currying, it's binding. auto plus5rhs = bind!(plus, 2)(5); etc. Andrei
Feb 24 2009
prev sibling next sibling parent reply Yigal Chripun <dude sweet.com> writes:
Andrei Alexandrescu Wrote:
 
 I'd agree that generally there's a strong bias in this group for adding 
 to the language. Every itsy-bitsy issue comes around, there are a dozen 
 cute syntaxes invented for it right on the spot. And then once every few 
 months, there's the inevitable huge thread "Where did my simple language 
 go???" :o)

I disagree with this notion. there are requests to add new *useful* features but there are also requests to remove unneeded features, latest was the discussion of the implicit concatenation of string literals. There was a thread not long ago listing the features most people want to remove - foreach_reverse comes to mind. that how evolution works - you add new useful stuff and remove old unneeded baggage. both are equally important.
 Currying/binding can be done easily with a library, and the 
 implementation is so simple there's no need for a separate file 
 dedicated to it. The one interesting case is currying a function passed 
 by alias. In that case there's no indirect call, just a little struct 
 created that contains the curried state:
 
 int plus(int x, int y} { return x + y; }
 auto plus5 = curry!(plus)(5);
 assert(plus5(10) == 15);
 
 typeof(plus5) will be a little struct that may be cumbersome to pass 
 around, in which case you do want to take the toll of the indirect call 
 by writing:
 
 auto plus5 = makeDelegate(curry!(plus)(5));
 assert(is(typeof(plus5) == int delegate(int));
 assert(plus5(10) == 15);
 
 This stuff belongs to std.functional. I plan to eliminate std.bind and 
 put currying and binding in std.functional. What do people think?
 
 Andrei 

Feb 24 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Yigal Chripun wrote:
 Andrei Alexandrescu Wrote:
 I'd agree that generally there's a strong bias in this group for adding 
 to the language. Every itsy-bitsy issue comes around, there are a dozen 
 cute syntaxes invented for it right on the spot. And then once every few 
 months, there's the inevitable huge thread "Where did my simple language 
 go???" :o)

I disagree with this notion. there are requests to add new *useful* features but there are also requests to remove unneeded features, latest was the discussion of the implicit concatenation of string literals. There was a thread not long ago listing the features most people want to remove - foreach_reverse comes to mind. that how evolution works - you add new useful stuff and remove old unneeded baggage. both are equally important.

There's a much stronger bias to add than remove, and IMHO adding to the language for currying is just unnecessary. I'll venture the thought that for those who don't use the language often enough it's not easy to envision how something could be implemented within it, and inventing a new specialized feature for the problem at hand comes very easily. Andrei
Feb 24 2009
parent bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:
 There's a much stronger bias to add than remove,

Yes, unfortunately with time most (or all) languages tend to grow, and to become more complex and hairy. And often there's no way to fix this problem, the complexity keeps growing, until people want to create a better new language that finds better ways to do most of those things with less complexity. Even in language communities that value language simplicity and clarity above almost everything else like the Python community, where they are even willing to break the high-valued backward compatibility, they have created Python3 that removes as many warts and duplicated features as possible, yet, Python3 is more complex than Python 2.5 still. One of the big intrinsic disadvantages of the C++ and D languages is that they have a lot of near-duplicated features, one feature from C and one new way to do essentially the same thing. This of course has some advantages (C compatibility first of all, but also the old C features are often the more efficient ones, when you really need max performance). Regarding binding and currying and other functional features, you/we have to decide the future taste of D2. If people want to make D2 more functional-tasting, then some functional features may be better as built-ins. Regardless your choice, I suggest all D designers to often look at the Scala language (and F#, if you want) (and to not look at Java much anymore). Scala is far from perfect, and in some regards may already be too much complex, but it shows interesting ways to mix OOP, mutation, actor-based multiprocessing, and strong functional features with a type system much more refined than the current one used in D2. So it partly shows how D2 or D3 may look. To be more precise, I now think D2 doesn't need much the pattern matching (because it's useful but it also adds a significant amount of complexity to the language), but it may enjoy to gain Algebraic Data Types (http://en.wikipedia.org/wiki/Algebraic_data_type ), more than AST macros. ADTs too add complexity and require a more complex type system, but they allow a functional-flavored language (as Scala, F#, Ocaml, and many pure-FP languages) to express several things in a quite compact way, add power to the language, etc :-) Bye, bearophile
Feb 24 2009
prev sibling next sibling parent Lars Kyllingstad <public kyllingen.NOSPAMnet> writes:
Andrei Alexandrescu wrote:
 Daniel Keep wrote:
 The problem I have with these suggestions are that you're basically
 arguing for an incredibly inflexible, context-dependant, completely
 unintuitive syntax for something you already have working syntax for.  I
 just don't see the point.

I'd agree that generally there's a strong bias in this group for adding to the language. Every itsy-bitsy issue comes around, there are a dozen cute syntaxes invented for it right on the spot. And then once every few months, there's the inevitable huge thread "Where did my simple language go???" :o) Currying/binding can be done easily with a library, and the implementation is so simple there's no need for a separate file dedicated to it. The one interesting case is currying a function passed by alias. In that case there's no indirect call, just a little struct created that contains the curried state: int plus(int x, int y} { return x + y; } auto plus5 = curry!(plus)(5); assert(plus5(10) == 15); typeof(plus5) will be a little struct that may be cumbersome to pass around, in which case you do want to take the toll of the indirect call by writing: auto plus5 = makeDelegate(curry!(plus)(5)); assert(is(typeof(plus5) == int delegate(int)); assert(plus5(10) == 15); This stuff belongs to std.functional. I plan to eliminate std.bind and put currying and binding in std.functional. What do people think? Andrei

I like the syntax, and I agree that this belongs in std.functional. -Lars
Feb 25 2009
prev sibling parent reply Jason House <jason.james.house gmail.com> writes:
Andrei Alexandrescu Wrote:

 Daniel Keep wrote:
 The problem I have with these suggestions are that you're basically
 arguing for an incredibly inflexible, context-dependant, completely
 unintuitive syntax for something you already have working syntax for.  I
 just don't see the point.

I'd agree that generally there's a strong bias in this group for adding to the language. Every itsy-bitsy issue comes around, there are a dozen cute syntaxes invented for it right on the spot. And then once every few months, there's the inevitable huge thread "Where did my simple language go???" :o) Currying/binding can be done easily with a library, and the implementation is so simple there's no need for a separate file dedicated to it. The one interesting case is currying a function passed by alias. In that case there's no indirect call, just a little struct created that contains the curried state: int plus(int x, int y} { return x + y; } auto plus5 = curry!(plus)(5); assert(plus5(10) == 15); typeof(plus5) will be a little struct that may be cumbersome to pass around, in which case you do want to take the toll of the indirect call by writing: auto plus5 = makeDelegate(curry!(plus)(5)); assert(is(typeof(plus5) == int delegate(int)); assert(plus5(10) == 15); This stuff belongs to std.functional. I plan to eliminate std.bind and put currying and binding in std.functional. What do people think? Andrei

I've done the whole boost::bind thing before and it sucks. When boost::lambda came out, that was way better. Anonymous delegates are even better. Learning a separate functional syntax will always be a sub par solution to me. I'll go even further. If D had only what you've proposed for ranges and std.functional but lacked opApply and anonymous delegates, I never would have become a D user. Simple, clean syntax is that important to me... Please don't recreate boost and STL in D. They're great libraries, but we can do way better than that!
Feb 25 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jason House wrote:
 Andrei Alexandrescu Wrote:
 int plus(int x, int y} { return x + y; } auto plus5 =
 curry!(plus)(5); assert(plus5(10) == 15);
 
 typeof(plus5) will be a little struct that may be cumbersome to
 pass around, in which case you do want to take the toll of the
 indirect call by writing:
 
 auto plus5 = makeDelegate(curry!(plus)(5)); assert(is(typeof(plus5)
 == int delegate(int)); assert(plus5(10) == 15);
 
 This stuff belongs to std.functional. I plan to eliminate std.bind
 and put currying and binding in std.functional. What do people
 think?
 
 Andrei

I've done the whole boost::bind thing before and it sucks. When boost::lambda came out, that was way better. Anonymous delegates are even better. Learning a separate functional syntax will always be a sub par solution to me.

So let's see. If what you have is a function int fun(int, int) and you want to fix its first parameter to a specific value, you can write: (int x) { return fun(42, x); } That would be a function literal. To give it a name, you can say: int gun(int x) { return fun(42, x); } If you want to pass that thing around, you take &gun (or &(literal)) and transform it into a delegate. One minor issue with the above is that the syntax is rather verbose and that the relationship between the function, the parameter, and the outcome is not conceptualized. Yes, the constructs can curry any function, but you have no *notion* of currying a function. So I thought of defining such a simple notion that would allow you to write: curry!(fun)(42) instead of the literals above. In your code you are of course free to use either form as you find fit, just as you can write x * x * x or cube(x) or pow(x, 3). So I'm not sure where the sub par thing comes.
 I'll go even further. If D had only what you've proposed for ranges
 and std.functional but lacked opApply and anonymous delegates, I
 never would have become a D user. Simple, clean syntax is that
 important to me...  Please don't recreate boost and STL in D.
 They're great libraries, but we can do way better than that!

This is the Usenet equivalent of a pie in the face. Wait, what? I _thought_ I'm far beyond recreating boost and STL and also that in the process I am using the full power of the language (and sometimes even more, as shown by the stream of bug reports and enhancement requests that I had to post recently). All range, functional, and algorithms do hinge on anonymous delegates (function literals in fact, which are considerably better); they don't compete with them at all, so I fail to see how one could be thought of in separation from the other. Anyhow, if you have some ideas on how we can do way better than the current trend I'm all ears. My perception, if you allow me to venture a thought, is that you are a bit confused. To paraphrase SICP, you are happy with x * x * x and are afraid that the option of writing cube(x) makes things worse. Andrei
Feb 25 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Denis Koroskin wrote:
 On Wed, 25 Feb 2009 17:19:30 +0300, Andrei Alexandrescu 
 curry!(fun)(42)

 instead of the literals above.

I don't want to offend anyone, but this syntax sucks badly. Just compare: auto x = (int x) { return fun(42, x); }; auto x = makeDelegate(curry!(fun)(42)); And you say that your solution is /shorter/? You must be kidding!

Of course it is shorter. You seldom need makeDelegate. And the more parameters you add to the mix, the shorter it becomes.
 Delegate is THE way to pass closures in D, not some functional object 
 that has opCall().

Who told you that lied.
 Besides, I want my methods to be virtual and I can't 
 afford myself a template method that accepts functional objects of any 
 type.

Sure. Make a delegate out of it when you so need. Notice that *I* don't want to be shoehorned into making only virtual calls.
 bind is way *way* WAY more capable that what you propose as a 
 replacement. It allows parameter reordering, duplication etc with a 
 simple, uniform syntax:
 
 auto x = bind(&fun, 42, _0);
 auto y = bind(&fun, _0, 42);
 auto z = bind(&fun, _1, _0);

I'm not sure how you can say that because you don't know about the replacement I want to propose. Even I don't fully know. I tried to launch a thread asking people for designs, met with a thundering silence (in contrast, ironically, there's been a lot of interest in creating ad-hoc syntax). Anyway, I was thinking of: auto x = bind!(fun, 0)(42); auto y = bind!(fun, 1)(42); Rewiring arguments would be the charter of a different functional.
 But it's not very intuitive and easy to read:
 
 auto q = bind(&fun, _1, bind(&fun, bind(&fun, _0, 42), _1));

I agree :o). I wanted to come up with an equivalent, but couldn't actually figure what yours does. For example, where does the first parameter of the outer bind go? Did you mean _0 instead of the first _1?
 Besides, it is often ambiguous:
 
 void foo(int x, int y);
 void foo(float x, int y);
 
 auto x = makeDelegate(bind(&foo, _0, 42)); // error
 
 With built-in D delegate syntax, there is no ambiguity and mistake:
 auto x = (int x) { foo(x, 42); };
 
 That's *the best* syntax I can think of. Just keep it and let the 
 std.bind go. Don't waste your precious time of fixing something that 
 isn't broken (err.. std.bind IS broken, but that's not what I was 
 talking about :p)

Well no matter how the conversation went, I'm hugely drawn to a conclusion that has me do less work :o). Andrei
Feb 25 2009
parent Georg Wrede <georg.wrede iki.fi> writes:
Andrei Alexandrescu wrote:
 I tried to launch a thread asking people for designs, met with a 
 thundering silence (in contrast, ironically, there's been a lot of 
 interest in creating ad-hoc syntax).

If you're referring to your post earlier in this thread, where you wrote:
 So, I'm renaming this thread and launching a design contest for the
 new std.bind. First step: how should the interface look like?

then it is possible that the post did not gather the impact and readers that you expected. Most of us are pressed for time, so a boring thread on "std.bind documentation sucks hard" is not what we choose to open first. A mere leaf in such a tree risks lack of exposure. Also, a leaf-level post lacks implicit urgency and prestige. Another thing is of course, a design contest needs several days at least to produce any results. And many took the post as soliciting for programming of such a bind library, as opposed to merely posting one's wishes of usage syntax.
Feb 25 2009
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Andrei Alexandrescu Wrote:

 Jason House wrote:
 Andrei Alexandrescu Wrote:
 int plus(int x, int y} { return x + y; } auto plus5 =
 curry!(plus)(5); assert(plus5(10) == 15);
 
 typeof(plus5) will be a little struct that may be cumbersome to
 pass around, in which case you do want to take the toll of the
 indirect call by writing:
 
 auto plus5 = makeDelegate(curry!(plus)(5)); assert(is(typeof(plus5)
 == int delegate(int)); assert(plus5(10) == 15);
 
 This stuff belongs to std.functional. I plan to eliminate std.bind
 and put currying and binding in std.functional. What do people
 think?
 
 Andrei

I've done the whole boost::bind thing before and it sucks. When boost::lambda came out, that was way better. Anonymous delegates are even better. Learning a separate functional syntax will always be a sub par solution to me.

So let's see. If what you have is a function int fun(int, int) and you want to fix its first parameter to a specific value, you can write: (int x) { return fun(42, x); } That would be a function literal. To give it a name, you can say: int gun(int x) { return fun(42, x); } If you want to pass that thing around, you take &gun (or &(literal)) and transform it into a delegate. One minor issue with the above is that the syntax is rather verbose and that the relationship between the function, the parameter, and the outcome is not conceptualized. Yes, the constructs can curry any function, but you have no *notion* of currying a function. So I thought of defining such a simple notion that would allow you to write: curry!(fun)(42) instead of the literals above. In your code you are of course free to use either form as you find fit, just as you can write x * x * x or cube(x) or pow(x, 3). So I'm not sure where the sub par thing comes.
 I'll go even further. If D had only what you've proposed for ranges
 and std.functional but lacked opApply and anonymous delegates, I
 never would have become a D user. Simple, clean syntax is that
 important to me...  Please don't recreate boost and STL in D.
 They're great libraries, but we can do way better than that!

This is the Usenet equivalent of a pie in the face.

Sorry about that. I'm sleep deprived and working extra long hours at work lately.
 Wait, what? I 
 _thought_ I'm far beyond recreating boost and STL and also that in the 
 process I am using the full power of the language (and sometimes even 
 more, as shown by the stream of bug reports and enhancement requests 
 that I had to post recently). All range, functional, and algorithms do 
 hinge on anonymous delegates (function literals in fact, which are 
 considerably better); they don't compete with them at all, so I fail to 
 see how one could be thought of in separation from the other. Anyhow, if 
 you have some ideas on how we can do way better than the current trend 
 I'm all ears. My perception, if you allow me to venture a thought, is 
 that you are a bit confused. To paraphrase SICP, you are happy with x * 
 x * x and are afraid that the option of writing cube(x) makes things worse.

The first follow-up to your reply captured the kind of messiness bind can bring in C++. So far, all your examples are trivial (lack argument reordering, function composition, etc...). It's true that your examples look clean, but the devil will be in the details. I'd give better examples/details if I wasn't typing this with my thumb into a cell phone... I'm normally a man of few words, but that makes me give less detail than I otherwise would.
 Andrei

Feb 25 2009
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Jason House wrote:
 I'd give better examples/details if I wasn't typing this with my thumb into a
cell phone...

You do caps, quotes, special characters, correct grammar with your thumb on a cell phone?! I'm impressed! I can't bother with that without a full keyboard. Doing text on a phone keypad is agony for me. <rant> I have several devices, like a dvd recorder, game box, etc., that need text entry. Each has their own kludge-o-matic way of doing it with the remote. They're all horrible and agonizingly slow. Can't any of them put a gawd-dammed USB port on so I can plug in a keyboard? Or a PS/2 keyboard port? Or even, dare I say it, a morse key? http://www.freepatentsonline.com/6418323.html </rant>
Feb 25 2009
next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Jarrett Billingsley wrote:
 There are cell phones with QWERTY keypads (or touchscreens) now, you know ;)

I am soo obsolete <g>! My cell phone has a number pad on it. When I even bother to put a charge on it.
Feb 25 2009
prev sibling next sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
Walter Bright wrote:
 Jason House wrote:
 I'd give better examples/details if I wasn't typing this with my thumb 
 into a cell phone...

You do caps, quotes, special characters, correct grammar with your thumb on a cell phone?! I'm impressed! I can't bother with that without a full keyboard. Doing text on a phone keypad is agony for me. <rant> I have several devices, like a dvd recorder, game box, etc., that need text entry. Each has their own kludge-o-matic way of doing it with the remote. They're all horrible and agonizingly slow. Can't any of them put a gawd-dammed USB port on so I can plug in a keyboard? Or a PS/2 keyboard port? Or even, dare I say it, a morse key? http://www.freepatentsonline.com/6418323.html </rant>

Playstation 3 (and possibly Playstation 2) has USB ports and USB HID support. I've hooked up an IBM Model M to one (using a ps/2 -> usb adapter). Playstation 3 is also a reasonably-priced bluray player.
Feb 25 2009
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Christopher Wright wrote:
 Walter Bright wrote:
 Jason House wrote:
 I'd give better examples/details if I wasn't typing this with my
 thumb into a cell phone...

You do caps, quotes, special characters, correct grammar with your thumb on a cell phone?! I'm impressed! I can't bother with that without a full keyboard. Doing text on a phone keypad is agony for me. <rant> I have several devices, like a dvd recorder, game box, etc., that need text entry. Each has their own kludge-o-matic way of doing it with the remote. They're all horrible and agonizingly slow. Can't any of them put a gawd-dammed USB port on so I can plug in a keyboard? Or a PS/2 keyboard port? Or even, dare I say it, a morse key? http://www.freepatentsonline.com/6418323.html </rant>

Playstation 3 (and possibly Playstation 2) has USB ports and USB HID support. I've hooked up an IBM Model M to one (using a ps/2 -> usb adapter). Playstation 3 is also a reasonably-priced bluray player.

The XBox 360 supports keyboards as well, although not mice (I understand the PS3 does support mice in some games.) This sucks as it makes the machine useless for first person shooters. :P The Wii also has support for keyboards, although I'm only aware of it actually working in the web browser. As an interesting side note, the 360 is the only current-gen console that can't browse the web. You'd think MS would have jumped at the chance to put IE on yet another platform... -- Daniel
Feb 25 2009
prev sibling parent Jason House <jason.james.house gmail.com> writes:
Walter Bright wrote:

 Jason House wrote:
 I'd give better examples/details if I wasn't typing this with my thumb
 into a cell phone...

You do caps, quotes, special characters, correct grammar with your thumb on a cell phone?! I'm impressed! I can't bother with that without a full keyboard. Doing text on a phone keypad is agony for me.

Who says I don't have a full keyboard? Ok, well, it's a tiny keyboard on a touch screen. The iPhone interface is one of the nicest I've used. I've always had the bad habit of trying to write properly even when I had a keypad. K9 was a godsend, but a "normal" keyboard is even better. PS: This post was with a real computer. It's a rare luxury with a little baby in the house that is usually spent working on my D code instead of doing newsgroup stuff :)
Feb 25 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jason House wrote:
 The first follow-up to your reply captured the kind of messiness bind
 can bring in C++. So far, all your examples are trivial (lack
 argument reordering, function composition, etc...). It's true that
 your examples look clean, but the devil will be in the details.

I see. The only problem is that very few people seem to use std.bind; there are few interesting examples of arbitrary partial argument binding that need formalization. The one good example I know of is those float vector permutations, but nobody in their right mind would use a delegate for that! That all makes it even more appealing to stick with a five-liner in std.functional that gets currying into the bag (which is a useful and low-hanging fruit) and call std.bind history. Makes sense? Andrei
Feb 25 2009
next sibling parent Jason House <jason.james.house gmail.com> writes:
Andrei Alexandrescu wrote:

 Jason House wrote:
 The first follow-up to your reply captured the kind of messiness bind
 can bring in C++. So far, all your examples are trivial (lack
 argument reordering, function composition, etc...). It's true that
 your examples look clean, but the devil will be in the details.

I see. The only problem is that very few people seem to use std.bind; there are few interesting examples of arbitrary partial argument binding that need formalization. The one good example I know of is those float vector permutations, but nobody in their right mind would use a delegate for that!

I was one of those people using bind when I was using D1, and I didn't actually use std.bind... I think what is really needed before a design contest is to know what the use cases are. If there's only one use case, I'd argue that completely generic terms such as curry are not appropriate.
 That all makes it even more appealing to stick with a five-liner in
 std.functional that gets currying into the bag (which is a useful and
 low-hanging fruit) and call std.bind history. Makes sense?

The few lines of code for a single case does make sense. I can't yet figure out what you're thinking the final product should be or what it should do. When talking about bind, I think of boost::bind (or std::bind). When thinking of that, I envision all the ugly combinations that can arise. I usually think of delegates as solving those cases better. I also would have assumed that when you talked about small structs that you'd be using the opCall trick (or similar). Of course, we all know you don't like adding parenthesis at the end, so maybe a function name would be better ;) ... so no, it doesn't make sense.
Feb 25 2009
prev sibling parent Don <nospam nospam.com> writes:
Andrei Alexandrescu wrote:
 Jason House wrote:
 The first follow-up to your reply captured the kind of messiness bind
 can bring in C++. So far, all your examples are trivial (lack
 argument reordering, function composition, etc...). It's true that
 your examples look clean, but the devil will be in the details.

I see. The only problem is that very few people seem to use std.bind; there are few interesting examples of arbitrary partial argument binding that need formalization. The one good example I know of is those float vector permutations, but nobody in their right mind would use a delegate for that! That all makes it even more appealing to stick with a five-liner in std.functional that gets currying into the bag (which is a useful and low-hanging fruit) and call std.bind history. Makes sense? Andrei

Yes. I think that the smaller Phobos can be, the better. Make sure that everything in it is actually useful, and ditch the rest.
Feb 26 2009
prev sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-02-25 14:36:43 -0500, "Denis Koroskin" <2korden gmail.com> said:

 With built-in D delegate syntax, there is no ambiguity and mistake:
 auto x = (int x) { foo(x, 42); };
 
 That's *the best* syntax I can think of. Just keep it and let the 
 std.bind  go. Don't waste your precious time of fixing something that 
 isn't broken  (err.. std.bind IS broken, but that's not what I was 
 talking about :p)

I pretty much agree with this. What's great about this is that you just reuse your knowleadge of functions instead of having to learn something new. The mental load is thus smaller; this is much more important than saving a few characters. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Feb 25 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Wed, Feb 25, 2009 at 5:50 PM, Walter Bright
<newshound1 digitalmars.com> wrote:

 You do caps, quotes, special characters, correct grammar with your thumb on
 a cell phone?! I'm impressed! I can't bother with that without a full
 keyboard. Doing text on a phone keypad is agony for me.

There are cell phones with QWERTY keypads (or touchscreens) now, you know ;)
Feb 25 2009
prev sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Thu, Feb 26, 2009 at 9:21 AM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 Jason House wrote:
 The first follow-up to your reply captured the kind of messiness bind
 can bring in C++. So far, all your examples are trivial (lack
 argument reordering, function composition, etc...). It's true that
 your examples look clean, but the devil will be in the details.

I see. The only problem is that very few people seem to use std.bind; there are few interesting examples of arbitrary partial argument binding that need formalization. The one good example I know of is those float vector permutations, but nobody in their right mind would use a delegate for that! That all makes it even more appealing to stick with a five-liner in std.functional that gets currying into the bag (which is a useful and low-hanging fruit) and call std.bind history. Makes sense?

I think simple is fine here. About the only places I've used boost::bind in C++ are things that I would never use a bind library to do in D, since in D we have nested functions and delegates. Those things knock about 80% of the wind out of a bind library in my opinion. --bb
Feb 25 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 24 Feb 2009 15:58:18 +0300, Yigal Chripun <yigal100 gmail.com>  
wrote:

 downs wrote:
 Yigal Chripun wrote:
 Lars Kyllingstad wrote:
 I've always thought currying was the main point of std.bind. If I'm  
 not
 mistaken, currying is commonly a built-in feature of functional
 programming languages, so if anything, std.bind could become more
 useful/important in D2 than in D1.

 I agree that the std.bind API could and should be improved.

 -Lars

int foo(int a, int b) { ... } int bar(int a) { return foo(a, _value); } // curry with some _value Other languages provide useful syntax sugar for currying: auto bar2 = foo(_, 500); bar2 here will be a delegate that will do the the same as the above bar.

Just for comparison' sake: auto dg =&foo /rfix/ somevar; // 1.0, tools auto dg = _bind(&foo, _1, somevar); // 1.0, std.bind auto dg = (int a) { return foo(a, somevar); }; // 2.0, literal

So does that mean you like the above suggestion? after all, it's shorter and clearer than all the other alternatives.. ;)

void foo(int x, int y) { ... } void foo(float x, int y) { ... } auto dg = foo(_, 0); // which one is picked?
Feb 24 2009
prev sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Wed, 25 Feb 2009 17:19:30 +0300, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Jason House wrote:
 Andrei Alexandrescu Wrote:
 int plus(int x, int y} { return x + y; } auto plus5 =
 curry!(plus)(5); assert(plus5(10) == 15);
  typeof(plus5) will be a little struct that may be cumbersome to
 pass around, in which case you do want to take the toll of the
 indirect call by writing:
  auto plus5 = makeDelegate(curry!(plus)(5)); assert(is(typeof(plus5)
 == int delegate(int)); assert(plus5(10) == 15);
  This stuff belongs to std.functional. I plan to eliminate std.bind
 and put currying and binding in std.functional. What do people
 think?
  Andrei

boost::lambda came out, that was way better. Anonymous delegates are even better. Learning a separate functional syntax will always be a sub par solution to me.

So let's see. If what you have is a function int fun(int, int) and you want to fix its first parameter to a specific value, you can write: (int x) { return fun(42, x); } That would be a function literal. To give it a name, you can say: int gun(int x) { return fun(42, x); } If you want to pass that thing around, you take &gun (or &(literal)) and transform it into a delegate. One minor issue with the above is that the syntax is rather verbose and that the relationship between the function, the parameter, and the outcome is not conceptualized. Yes, the constructs can curry any function, but you have no *notion* of currying a function. So I thought of defining such a simple notion that would allow you to write: curry!(fun)(42) instead of the literals above.

I don't want to offend anyone, but this syntax sucks badly. Just compare: auto x = (int x) { return fun(42, x); }; auto x = makeDelegate(curry!(fun)(42)); And you say that your solution is /shorter/? You must be kidding! Delegate is THE way to pass closures in D, not some functional object that has opCall(). Besides, I want my methods to be virtual and I can't afford myself a template method that accepts functional objects of any type. bind is way *way* WAY more capable that what you propose as a replacement. It allows parameter reordering, duplication etc with a simple, uniform syntax: auto x = bind(&fun, 42, _0); auto y = bind(&fun, _0, 42); auto z = bind(&fun, _1, _0); But it's not very intuitive and easy to read: auto q = bind(&fun, _1, bind(&fun, bind(&fun, _0, 42), _1)); Besides, it is often ambiguous: void foo(int x, int y); void foo(float x, int y); auto x = makeDelegate(bind(&foo, _0, 42)); // error With built-in D delegate syntax, there is no ambiguity and mistake: auto x = (int x) { foo(x, 42); }; That's *the best* syntax I can think of. Just keep it and let the std.bind go. Don't waste your precious time of fixing something that isn't broken (err.. std.bind IS broken, but that's not what I was talking about :p)
 In your code you are of course free to use either form as you find fit,  
 just as you can write x * x * x or cube(x) or pow(x, 3). So I'm not sure  
 where the sub par thing comes.

 I'll go even further. If D had only what you've proposed for ranges
 and std.functional but lacked opApply and anonymous delegates, I
 never would have become a D user. Simple, clean syntax is that
 important to me...  Please don't recreate boost and STL in D.
 They're great libraries, but we can do way better than that!

This is the Usenet equivalent of a pie in the face. Wait, what? I _thought_ I'm far beyond recreating boost and STL and also that in the process I am using the full power of the language (and sometimes even more, as shown by the stream of bug reports and enhancement requests that I had to post recently). All range, functional, and algorithms do hinge on anonymous delegates (function literals in fact, which are considerably better); they don't compete with them at all, so I fail to see how one could be thought of in separation from the other. Anyhow, if you have some ideas on how we can do way better than the current trend I'm all ears. My perception, if you allow me to venture a thought, is that you are a bit confused. To paraphrase SICP, you are happy with x * x * x and are afraid that the option of writing cube(x) makes things worse. Andrei

Feb 25 2009