www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Anonymous function syntax

reply Walter Bright <newshound2 digitalmars.com> writes:
I've collected a few from various languages for comparison:

D
     (a,b) { return a + b; }

Ruby
     ->(a,b) { a + b }

C++0x
     [](int a, int b) { return a + b; }

C#
     (a,b) => a + b

Scala
     (a:Int, b:Int) => a + b

Erlang
     fun(a, b) -> a + b end.

Haskell
     \a b -> a + b

Javascript
     function(a,b) { return a + b; }

Clojure
     # (+ % %2)

Lua
     function(a,b) return a + b end

Python
     lambda a,b: a + b
Sep 21 2011
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:

 D
      (a,b) { return a + b; }

In D to define a true lambda you need types too: auto f = (int a,int b){ return a + b; }; For D I think I'd like a syntax like: { int a, int b => a + b } That in some cases becomes just: { a,b => a + b }
 Haskell
      \a b -> a + b

In Haskell you often don't use lambdas. You curry functions, or your use already written little higher order functions/operators to build something, or sometimes you use list comprehensions: http://www.haskell.org/haskellwiki/List_comprehension take 10 [ (i,j) | i <- [1..], let k = i*i, j <- [1..k]] In Python too you often use list comprehensions instead of lambdas + filter + map. Bye, bearophile
Sep 21 2011
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 22/09/2011 00:29, bearophile a écrit :
 Walter Bright:

 D
       (a,b) { return a + b; }

In D to define a true lambda you need types too: auto f = (int a,int b){ return a + b; }; For D I think I'd like a syntax like: { int a, int b => a + b } That in some cases becomes just: { a,b => a + b }

That would be less readable for somebody coming from a C styled language. Curly braces for body and parenthesis for arguments is something very familiar. This makes Javascript's and D's closures the most readable for somebody having this background.
Sep 21 2011
next sibling parent Adam Ruppe <destructionator gmail.com> writes:
deadalnix wrote:
 This makes Javascript's and D's closures the most readable for
 somebody having this background.

Indeed! I find most the proposed lambdas to look like random noise. D has it good just how it is.
Sep 21 2011
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/22/2011 12:47 AM, deadalnix wrote:
 Le 22/09/2011 00:29, bearophile a écrit :
 Walter Bright:

 D
 (a,b) { return a + b; }

In D to define a true lambda you need types too: auto f = (int a,int b){ return a + b; };


If you leave types away, you in fact create a function template literal. Interestingly those only work for templates so far. I'd like them to work at other places, eg when the argument types are clear from the type signature of a function the delegate gets passed to. void foo(int delegate(int)){} void main(){ foo((a){return a;}); // this could work }
 For D I think I'd like a syntax like:
 { int a, int b => a + b }
 That in some cases becomes just:
 { a,b => a + b }


Then you'd probably have map!{a => 2*a}(range); That is very easy on the eyes. +1. What about: void foo(int delegate(int)){} void main(){ foo{a=>2*a}; // ok? } Is binary '{' worth spending like that?
 That would be less readable for somebody coming from a C styled
 language. Curly braces for body and parenthesis for arguments is
 something very familiar.

 This makes Javascript's and D's closures the most readable for somebody
 having this background.

The delegates themselves are very readable indeed but they tend to screw up the readability of larger expressions that contain them. An alternate delegate syntax could help a great deal in these cases.
Sep 21 2011
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/21/11 5:29 PM, bearophile wrote:
 Walter Bright:

 D
       (a,b) { return a + b; }

In D to define a true lambda you need types too: auto f = (int a,int b){ return a + b; };

No. Andrei
Sep 21 2011
parent reply Jacob Carlborg <doob me.com> writes:
On 2011-09-22 00:50, Andrei Alexandrescu wrote:
 On 9/21/11 5:29 PM, bearophile wrote:
 Walter Bright:

 D
 (a,b) { return a + b; }

In D to define a true lambda you need types too: auto f = (int a,int b){ return a + b; };

No. Andrei

void foo (int delegate (int, int) a){} void main () { foo((a, b) { return a +b;}); } Results in: main.d(48): Error: undefined identifier a main.d(48): Error: undefined identifier b main.d(48): Error: function main.foo (int delegate(int, int) a) is not callable using argument types (_error_ delegate(_error_, _error_)) main.d(48): Error: cannot implicitly convert expression (__dgliteral1) of type _error_ delegate(_error_, _error_) to int delegate(int, int) Failed: /Users/jacob/.dvm/bin/dvm-current-dc -v -o- '/Users/jacob/development/d/main.d' -I'/Users/jacob/development/d'
/Users/jacob/development/d/main.d.deps

-- /Jacob Carlborg
Sep 22 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/22/11 3:49 AM, Jacob Carlborg wrote:
 On 2011-09-22 00:50, Andrei Alexandrescu wrote:
 On 9/21/11 5:29 PM, bearophile wrote:
 Walter Bright:

 D
 (a,b) { return a + b; }

In D to define a true lambda you need types too: auto f = (int a,int b){ return a + b; };

No. Andrei

void foo (int delegate (int, int) a){} void main () { foo((a, b) { return a +b;}); } Results in: main.d(48): Error: undefined identifier a main.d(48): Error: undefined identifier b main.d(48): Error: function main.foo (int delegate(int, int) a) is not callable using argument types (_error_ delegate(_error_, _error_)) main.d(48): Error: cannot implicitly convert expression (__dgliteral1) of type _error_ delegate(_error_, _error_) to int delegate(int, int) Failed: /Users/jacob/.dvm/bin/dvm-current-dc -v -o- '/Users/jacob/development/d/main.d' -I'/Users/jacob/development/d' >/Users/jacob/development/d/main.d.deps

That's a bug in the compiler. Andrei
Sep 22 2011
parent reply Jacob Carlborg <doob me.com> writes:
On 2011-09-22 16:11, Andrei Alexandrescu wrote:
 On 9/22/11 3:49 AM, Jacob Carlborg wrote:
 On 2011-09-22 00:50, Andrei Alexandrescu wrote:
 On 9/21/11 5:29 PM, bearophile wrote:
 Walter Bright:

 D
 (a,b) { return a + b; }

In D to define a true lambda you need types too: auto f = (int a,int b){ return a + b; };

No. Andrei

void foo (int delegate (int, int) a){} void main () { foo((a, b) { return a +b;}); } Results in: main.d(48): Error: undefined identifier a main.d(48): Error: undefined identifier b main.d(48): Error: function main.foo (int delegate(int, int) a) is not callable using argument types (_error_ delegate(_error_, _error_)) main.d(48): Error: cannot implicitly convert expression (__dgliteral1) of type _error_ delegate(_error_, _error_) to int delegate(int, int) Failed: /Users/jacob/.dvm/bin/dvm-current-dc -v -o- '/Users/jacob/development/d/main.d' -I'/Users/jacob/development/d'
/Users/jacob/development/d/main.d.deps


That's a bug in the compiler. Andrei

Ok, has that been reported? -- /Jacob Carlborg
Sep 22 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/22/11 9:17 AM, Jacob Carlborg wrote:
 void foo (int delegate (int, int) a){}

 void main ()
 {
 foo((a, b) { return a +b;});
 }

 Results in:

 main.d(48): Error: undefined identifier a
 main.d(48): Error: undefined identifier b
 main.d(48): Error: function main.foo (int delegate(int, int) a) is not
 callable using argument types (_error_ delegate(_error_, _error_))
 main.d(48): Error: cannot implicitly convert expression (__dgliteral1)
 of type _error_ delegate(_error_, _error_) to int delegate(int, int)
 Failed: /Users/jacob/.dvm/bin/dvm-current-dc -v -o-
 '/Users/jacob/development/d/main.d' -I'/Users/jacob/development/d'
/Users/jacob/development/d/main.d.deps


That's a bug in the compiler. Andrei

Ok, has that been reported?

Yes :o). http://d.puremagic.com/issues/show_bug.cgi?id=6714 Andrei
Sep 22 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 Yes :o). http://d.puremagic.com/issues/show_bug.cgi?id=6714

Thank you for adding it, and sorry for not filing it myself in past. Bye, bearophile
Sep 22 2011
prev sibling parent reply Jesse Phillips <jessekphillips+d gmail.com> writes:
On Wed, 21 Sep 2011 18:29:34 -0400, bearophile wrote:

 Walter Bright:
 
 D
      (a,b) { return a + b; }

In D to define a true lambda you need types too: auto f = (int a,int b){ return a + b; };

This is true of C# too and I think is appropriate to mention, though it can take the destination type into account when doing inference.
 For D I think I'd like a syntax like: { int a, int b => a + b }
 That in some cases becomes just:
 { a,b => a + b }

I'd rather the C which is basically the same as D already.
Sep 21 2011
parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/21/2011 8:10 PM, Jesse Phillips wrote:
 On Wed, 21 Sep 2011 18:29:34 -0400, bearophile wrote:

 Walter Bright:

 D
       (a,b) { return a + b; }

In D to define a true lambda you need types too: auto f = (int a,int b){ return a + b; };

This is true of C# too and I think is appropriate to mention, though it can take the destination type into account when doing inference.

As Andrei pointed out, it is not true of D, since D does not require the types for the parameters.
Sep 22 2011
prev sibling next sibling parent reply Max Klyga <max.klyga gmail.com> writes:
Actually Scala doesn't need type declarations in labmda literals. Most 
of the time argument types are infered. It would be awesome if D 
infered argument types for labdas too.
Also Java 8 adopted the same lambda syntax as Scala and C#.

To add a few things to your list:

Nemerle
    fun (x, y) { x + y }
    (x, y) => x + y

Scala and Nemerle supports placeholder lambda syntax
    _ + _

Scheme
    (lambda (x y) (+ x y))

Smalltalk
    [ :x :y | x + y ]

ML/Ocaml/F#
    fun x y -> x + y

Ruby has a whole zoo of syntaxes
    {|x, y| x + y }
    ->(x, y) { x + y }
    do |x, y| x + y end

Groovy
    { x, y -> x + y }

So "(args) => body" is the most common syntax now
Sep 21 2011
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/21/2011 11:47 PM, Max Klyga wrote:
 It would be awesome if D infered argument types
 for labdas too.

It does, and it is awesome!
Sep 22 2011
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/22/2011 09:35 AM, Walter Bright wrote:
 On 9/21/2011 11:47 PM, Max Klyga wrote:
 It would be awesome if D infered argument types
 for labdas too.

It does, and it is awesome!

Indeed, but it currently only works if the delegate literal is a template parameter, in which case the literal is actually fully generic, right?
Sep 22 2011
parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/22/2011 4:36 AM, Timon Gehr wrote:
 Indeed, but it currently only works if the delegate literal is a template
 parameter, in which case the literal is actually fully generic, right?

It gets internally rewritten into being a template function.
Sep 22 2011
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/22/11 2:35 AM, Walter Bright wrote:
 On 9/21/2011 11:47 PM, Max Klyga wrote:
 It would be awesome if D infered argument types
 for labdas too.

It does, and it is awesome!

C++'s lambdas require the types to be present, which some consider a large mistake. Andrei
Sep 22 2011
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2011-09-22 08:47, Max Klyga wrote:
 Actually Scala doesn't need type declarations in labmda literals. Most
 of the time argument types are infered. It would be awesome if D infered
 argument types for labdas too.
 Also Java 8 adopted the same lambda syntax as Scala and C#.

 To add a few things to your list:

 Nemerle
 fun (x, y) { x + y }
 (x, y) => x + y

 Scala and Nemerle supports placeholder lambda syntax
 _ + _

 Scheme
 (lambda (x y) (+ x y))

 Smalltalk
 [ :x :y | x + y ]

 ML/Ocaml/F#
 fun x y -> x + y

 Ruby has a whole zoo of syntaxes
 {|x, y| x + y }
 ->(x, y) { x + y }
 do |x, y| x + y end

 Groovy
 { x, y -> x + y }

 So "(args) => body" is the most common syntax now

Scala also has this syntax that can be useful sometimes: foo { } Where "foo" is a method taking a delegate as an argument. This allows to create, what looks like, new statements. Which can be very handy for DSL's. -- /Jacob Carlborg
Sep 22 2011
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/22/11 1:47 AM, Max Klyga wrote:
 Actually Scala doesn't need type declarations in labmda literals. Most
 of the time argument types are infered.

Already does. We're looking for a briefer syntax. Andrei
Sep 22 2011
parent reply pillsy <pillsbury gmail.com> writes:
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article
 On 9/22/11 1:47 AM, Max Klyga wrote:
 Actually Scala doesn't need type declarations in labmda literals. Most
 of the time argument types are infered.


 Already does. We're looking for a briefer syntax.

What is the problem with just inferring the `return`, allowing you to replace (a,b) { return a + b; } with (a, b) { a + b; } This seems competitive with the other syntaxes for brevity, but ISTR there was some objection to doing things that way. Also would it make sense to have a template library along the lines of boost::proto/boost::lambda to allow even shorter, expression-based lambdas like _1 + _2 I'm not exactly a D template metaprogramming pro, but I think this would work for a lot of common cases. Cheers, Pillsy
Sep 22 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/22/11 10:42 AM, pillsy wrote:
 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article
 On 9/22/11 1:47 AM, Max Klyga wrote:
 Actually Scala doesn't need type declarations in labmda literals. Most
 of the time argument types are infered.


 Already does. We're looking for a briefer syntax.

What is the problem with just inferring the `return`, allowing you to replace (a,b) { return a + b; } with (a, b) { a + b; } This seems competitive with the other syntaxes for brevity, but ISTR there was some objection to doing things that way.

The objection is that it introduces a number of questions: 1. How about using that syntax in regular functions? 2. What if the lambda wants to actually evaluate the expression but return void? 3. How is the semicolon relevant? (If its presence is used as a disambiguator for (2), it's poor design to predicate a large semantic difference on such a distinction.)
 Also would it make sense to have a template library along the lines of
boost::proto/boost::lambda to allow even
 shorter, expression-based lambdas like

      _1 + _2

 I'm not exactly a D template metaprogramming pro, but I think this would work
for a lot of common cases.

Such an approach has caused more trouble than benefits in C++. Andrei
Sep 22 2011
next sibling parent pillsy <pillsbury gmail.com> writes:
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article
 On 9/22/11 10:42 AM, pillsy wrote:
 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article


 Already does. We're looking for a briefer syntax.



 What is the problem with just inferring the `return`, allowing you to replace


       (a,b) { return a + b; }


 with


      (a, b) { a + b; }


 This seems competitive with the other syntaxes for brevity, but ISTR there was
 some objection to doing things that way.


 The objection is that it introduces a number of questions:

At the risk of relitigating a long-settled issue, I think there are good answers to all these questions.
 1. How about using that syntax in regular functions?

That sounds great! :)
 2. What if the lambda wants to actually evaluate the expression but
 return void?

Is this commonly important? If so, there are three possibilities: a. Have an expression with type void, perhaps a `void` literal or empty patens `()`, that can be used as the ultimate expression when needed, as in (i) { total += i; void; } b. Require the use of a bare `return` in these cases. c. Require the return type to be explicitly declared as void in those cases. This seems like it's especially not a problem for named functions, since `void` isn't any longer than `auto.
 3. How is the semicolon relevant? (If its presence is used as a
 disambiguator for (2), it's poor design to predicate a large semantic
 difference on such a distinction.)

It's just part of the syntax. I agree that using it to disambiguate the function's return type is horrible. Mathematica does that, and I've torn out a fair amount of my hair because of it over the years. [...]
 I'm not exactly a D template metaprogramming pro, but I think this would work
for a lot of common cases.


Fair enough. Cheers, Pillsy
Sep 22 2011
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/22/2011 9:06 AM, Andrei Alexandrescu wrote:
 On 9/22/11 10:42 AM, pillsy wrote:
 _1 + _2

 I'm not exactly a D template metaprogramming pro, but I think this would work
 for a lot of common cases.

Such an approach has caused more trouble than benefits in C++.

Besides just looking awfully hackish.
Sep 22 2011
prev sibling next sibling parent Lutger Blijdestijn <lutger.blijdestijn gmail.com> writes:
Andrei Alexandrescu wrote:

 On 9/22/11 10:42 AM, pillsy wrote:
 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s
 article
 On 9/22/11 1:47 AM, Max Klyga wrote:
 Actually Scala doesn't need type declarations in labmda literals. Most
 of the time argument types are infered.


 Already does. We're looking for a briefer syntax.

What is the problem with just inferring the `return`, allowing you to replace (a,b) { return a + b; } with (a, b) { a + b; } This seems competitive with the other syntaxes for brevity, but ISTR there was some objection to doing things that way.

The objection is that it introduces a number of questions: 1. How about using that syntax in regular functions? 2. What if the lambda wants to actually evaluate the expression but return void?

As an alternative, a brief syntax could just be restricted to lambda expressions because we already have complete function literals for statements, unlike python for example. A void returning function is only used for side-effects, I am not be bothered at all to have to use full punctuation for that. (a, b) { a + b } or (a, b) => a + b would be sweet :)
Sep 22 2011
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2011-09-22 18:06, Andrei Alexandrescu wrote:
 On 9/22/11 10:42 AM, pillsy wrote:
 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s
 article
 On 9/22/11 1:47 AM, Max Klyga wrote:
 Actually Scala doesn't need type declarations in labmda literals. Most
 of the time argument types are infered.


 Already does. We're looking for a briefer syntax.

What is the problem with just inferring the `return`, allowing you to replace (a,b) { return a + b; } with (a, b) { a + b; } This seems competitive with the other syntaxes for brevity, but ISTR there was some objection to doing things that way.

The objection is that it introduces a number of questions: 1. How about using that syntax in regular functions? 2. What if the lambda wants to actually evaluate the expression but return void?

I function/delegate that returns a value should be implicitly converted to a function/delegate that returns void. -- /Jacob Carlborg
Sep 22 2011
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/22/2011 1:13 PM, Jacob Carlborg wrote:
 I function/delegate that returns a value should be implicitly converted to a
 function/delegate that returns void.

That doesn't work in some cases - consider a function that returns an object that the caller must destruct. Or even just returns a struct - the caller passes in a hidden pointer to where the return type gets written. Implicit conversion of function pointers and delegates requires binary ABI compatibility.
Sep 22 2011
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/22/2011 11:46 PM, Walter Bright wrote:
 On 9/22/2011 1:13 PM, Jacob Carlborg wrote:
 I function/delegate that returns a value should be implicitly
 converted to a
 function/delegate that returns void.

That doesn't work in some cases - consider a function that returns an object that the caller must destruct. Or even just returns a struct - the caller passes in a hidden pointer to where the return type gets written. Implicit conversion of function pointers and delegates requires binary ABI compatibility.

The compiler could insert a thunk that discards the result if the two delegate types are not ABI compatible.
Sep 22 2011
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2011-09-22 23:46, Walter Bright wrote:
 On 9/22/2011 1:13 PM, Jacob Carlborg wrote:
 I function/delegate that returns a value should be implicitly
 converted to a
 function/delegate that returns void.

That doesn't work in some cases - consider a function that returns an object that the caller must destruct. Or even just returns a struct - the caller passes in a hidden pointer to where the return type gets written.

What I'm saying is that you can ignore the returned value of a delegate therefore I think it should be possible implicitly convert a delegate returning a value, to a delegate returning void. The same for function pointers as well. Example: void main () { int delegate () bar = { return 1; }; void delegate () foo = bar; int a = bar(); // here we call "bar" and handles the return value bar(); // here we call "bar" and ignores the return value foo(); // here we call "foo", same as the line above } Or are you saying that it would be strange and confusing when calling a delegate that returns void, a struct could be destructed on the callers side? I can agree with that.
 Implicit conversion of function pointers and delegates requires binary
 ABI compatibility.

I'm not suggesting that a function pointer should be implicitly converted to a delegate, if that what is what you are saying. -- /Jacob Carlborg
Sep 22 2011
parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Jacob Carlborg" <doob me.com> wrote in message 
news:j5h98l$ors$1 digitalmars.com...
 What I'm saying is that you can ignore the returned value of a delegate 
 therefore I think it should be possible implicitly convert a delegate 
 returning a value, to a delegate returning void. The same for function 
 pointers as well. Example:

 void main ()
 {
     int delegate () bar = { return 1; };
     void delegate () foo = bar;

     int a = bar(); // here we call "bar" and handles the return value
     bar(); // here we call "bar" and ignores the return value
     foo(); // here we call "foo", same as the line above
 }

if the return value requires destruction by the caller? What if the return is done through nrvo? While they're called the same, the code generator handles them very differently. If it works, it should work for all cases. Don't forget that you can trivially convert to a delegate returning void with the following syntax: void delegate () foo = { bar(); };
Sep 22 2011
parent reply Jacob Carlborg <doob me.com> writes:
On 2011-09-23 08:42, Daniel Murphy wrote:
 "Jacob Carlborg"<doob me.com>  wrote in message
 news:j5h98l$ors$1 digitalmars.com...
 What I'm saying is that you can ignore the returned value of a delegate
 therefore I think it should be possible implicitly convert a delegate
 returning a value, to a delegate returning void. The same for function
 pointers as well. Example:

 void main ()
 {
      int delegate () bar = { return 1; };
      void delegate () foo = bar;

      int a = bar(); // here we call "bar" and handles the return value
      bar(); // here we call "bar" and ignores the return value
      foo(); // here we call "foo", same as the line above
 }

if the return value requires destruction by the caller? What if the return is done through nrvo? While they're called the same, the code generator handles them very differently. If it works, it should work for all cases. Don't forget that you can trivially convert to a delegate returning void with the following syntax: void delegate () foo = { bar(); };

Why can't the compiler do something similar automatically. Then we won't have the problem if a lambda returns void or a value. -- /Jacob Carlborg
Sep 22 2011
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/22/2011 11:55 PM, Jacob Carlborg wrote:
 On 2011-09-23 08:42, Daniel Murphy wrote:
 void delegate () foo = { bar(); };

Why can't the compiler do something similar automatically. Then we won't have the problem if a lambda returns void or a value.

1. This can get arbitrarily expensive if there are parameters involved (temps have to be constructed, copied, & destroyed) and those costs will be hidden. 2. At some point, heroic efforts to coerce one type to another will subvert the point of a type system. After all, if the designer of bar() intended the return value to be the point, wouldn't such a conversion hide a bug?
Sep 23 2011
parent Jacob Carlborg <doob me.com> writes:
On 2011-09-23 09:34, Walter Bright wrote:
 On 9/22/2011 11:55 PM, Jacob Carlborg wrote:
 On 2011-09-23 08:42, Daniel Murphy wrote:
 void delegate () foo = { bar(); };

Why can't the compiler do something similar automatically. Then we won't have the problem if a lambda returns void or a value.

1. This can get arbitrarily expensive if there are parameters involved (temps have to be constructed, copied, & destroyed) and those costs will be hidden.

I guess so.
 2. At some point, heroic efforts to coerce one type to another will
 subvert the point of a type system. After all, if the designer of bar()
 intended the return value to be the point, wouldn't such a conversion
 hide a bug?

Maybe, but so could not using the returned value as well. It sounds so easy in my head. -- /Jacob Carlborg
Sep 23 2011
prev sibling parent travert phare.normalesup.org (Christophe) writes:
Andrei Alexandrescu , dans le message (digitalmars.D:145023), a écrit :
 What is the problem with just inferring the `return`, allowing you to replace
       (a,b) { return a + b; }

 with
      (a, b) { a + b; }


 The objection is that it introduces a number of questions:
 
 1. How about using that syntax in regular functions?
 2. What if the lambda wants to actually evaluate the expression but 
 return void?
 3. How is the semicolon relevant? (If its presence is used as a 
 disambiguator for (2), it's poor design to predicate a large semantic 
 difference on such a distinction.)

I think such shortcut should be allowed only for one-liners. There is no gain not to write return if you already have several statements. The shortcut syntax should be (a, b) { expression }, and not (a, b) { statement } This way, you ensure that only one liners can use this syntax, so there is no abuse. It is true that the return type would depend on the presence of a semicolon, but the compiler will quickly complain if it expects a delegate returning void and gets a delegate returning a type, or vice-versa anyway.
 Also would it make sense to have a template library along the lines of
boost::proto/boost::lambda to allow even
 shorter, expression-based lambdas like

      _1 + _2

 I'm not exactly a D template metaprogramming pro, but I think this would work
for a lot of common cases.

Such an approach has caused more trouble than benefits in C++.

Too dangerous. std.algorithm uses a, b, c, etc, but it can only do that because it never checks the context: int b; double x; auto f = lambda { a * x + b } How many arguments does f take ? -- Christophe
Sep 23 2011
prev sibling next sibling parent travert phare.normalesup.org (Christophe) writes:
Walter Bright , dans le message (digitalmars.D:144959), a écrit :
 I've collected a few from various languages for comparison:
 
 D
      (a,b) { return a + b; }

Few ideas: (a,b){ a + b } Lambdas can avoid to type 'return'. returning void would be harder, except if to return void, you can just put the semicolon at the end (but it could be confusing). a, b -> a + b Introduce a -> "operator" to generate a delegate. Depending on the precedence, "(a,b) -> (a + b)" might be prefered. "(a,b -> a+b)" will be safer to use obviously. I prefer that instead of {a,b -> a+b} because the second adds a different meaning to {}, which is different from "statement grouping" and "function body". The => symbol is fine too, but looks like a mistyped comparison operator to me. -- Christophe
Sep 22 2011
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2011-09-22 00:17, Walter Bright wrote:
 I've collected a few from various languages for comparison:

 D
 (a,b) { return a + b; }

 Ruby
 ->(a,b) { a + b }

 C++0x
 [](int a, int b) { return a + b; }

 C#
 (a,b) => a + b

 Scala
 (a:Int, b:Int) => a + b

 Erlang
 fun(a, b) -> a + b end.

 Haskell
 \a b -> a + b

 Javascript
 function(a,b) { return a + b; }

 Clojure
 # (+ % %2)

 Lua
 function(a,b) return a + b end

 Python
 lambda a,b: a + b

I vote for the Scala/C# syntax. It's worth noting there's a couple of things going on except the syntax that I think is as equally important: * Inferred parameter types * Automatically return the last expression * No need for ending with a semicolon * One line lambdas can omit the braces Note that Scala can infer the parameter types. An additional question, do we want/need a new syntax for declaring lambda/delegate types? -- /Jacob Carlborg
Sep 22 2011
parent Jesse Phillips <jessekphillips+D gmail.com> writes:
Jacob Carlborg Wrote:

 * Inferred parameter types
 * Automatically return the last expression
 * No need for ending with a semicolon
 * One line lambdas can omit the braces
 
 Note that Scala can infer the parameter types.
 
 An additional question, do we want/need a new syntax for declaring 
 lambda/delegate types?
 
 -- 
 /Jacob Carlborg

The only issue I have with current syntax is return. The type inferring is a bug so... I've really enjoyed the current syntax options. I've used auto var = { /// function thing return asuth; }() for a more complex ?:
Sep 22 2011
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/21/11 5:17 PM, Walter Bright wrote:
 I've collected a few from various languages for comparison:

I think we should do the following: 1. Introduce a new token "=>" 2. Add this rewrite to the grammar: symbol => expression translates to (symbol) { return expression; } 3. Add this rewrite to the grammar: symbol1 symbol2 => expression translates to (symbol1 symbol2) { return expression; } 4. Add this rewrite to the grammar: (comma_separated_parms) => expression translates to (comma_separated_parms) => expression Each item in comma_separated_parms may be 1 or 2 symbols separated by whitespace. Example: (int a, b) => a + b is valid and translates to (int a, b) { return a + b; } 5. The expression cannot contain commas at top level; an unparenthesized comma is considered to finish expression, just like in a function call's argument list. For example: fun(int a => a + 1, a + 2) is interpreted as fun((int a => a + 1), (a + 2)) To use comma inside expression, add parens around it. 5. Remove bugs and limitations. A function literal may specify none, all, or some parameter types, and the compiler correctly figures out the appropriate template and non-template parameters. The literal subsequently converts to function pointer or delegate whenever there's a match of parameter and result types. Andrei
Sep 22 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/22/11 3:54 PM, Andrei Alexandrescu wrote:
 On 9/21/11 5:17 PM, Walter Bright wrote:
 I've collected a few from various languages for comparison:

I think we should do the following:

I can't believe I forgot an all-important aspect. A function literal should be comparable to another for equality. Two function literals are equal if they have the same token type sequence (up to alpha renaming) and use the same environment. Example: bool test(auto fun)() { return fun == (x, y => x + y); } unittest { assert(test!(a, b => a + b)()); } This will not be easy to implement (especially when environment dependencies come into play) but is necessary. Andrei
Sep 22 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 A function literal should be comparable to another for equality.

Are you willing to explain me why, and show an use case? Bye, bearophile
Sep 22 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 09/22/11 16:08, bearophile wrote:
 Andrei Alexandrescu:

 A function literal should be comparable to another for equality.

Are you willing to explain me why, and show an use case?

An important application is optimizing for specific lambdas (e.g. equality). For example, a substring search using equality for characters could use bitwise comparison. Andrei
Sep 22 2011
next sibling parent reply pillsy <pillsbury gmail.com> writes:
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s
article

 On 09/22/11 16:08, bearophile wrote:

 Andrei Alexandrescu:


 A function literal should be comparable to another for
 equality.



 Are you willing to explain me why, and show an use case?


 An important application is optimizing for specific lambdas (e.g.
 equality). For example, a substring search using equality for
 characters could use bitwise comparison.

Is there some reason this isn't better handled through templating mechanisms? It seems like this would primarily benefit picking better optimization strategies at *runtime*, which strikes me as a fairly esoteric use case. Cheers, Pillsy
Sep 23 2011
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 09/23/11 10:40, pillsy wrote:
 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s
 article

 On 09/22/11 16:08, bearophile wrote:

 Andrei Alexandrescu:


 A function literal should be comparable to another for
 equality.



 Are you willing to explain me why, and show an use case?


 An important application is optimizing for specific lambdas (e.g.
 equality). For example, a substring search using equality for
 characters could use bitwise comparison.

Is there some reason this isn't better handled through templating mechanisms? It seems like this would primarily benefit picking better optimization strategies at *runtime*, which strikes me as a fairly esoteric use case. Cheers, Pillsy

Forgot to mention - the comparison should work statically, i.e. inside a static if. Andrei
Sep 23 2011
prev sibling parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:j5ge8v$2a0h$1 digitalmars.com...
 On 09/22/11 16:08, bearophile wrote:
 Andrei Alexandrescu:

 A function literal should be comparable to another for equality.

Are you willing to explain me why, and show an use case?

An important application is optimizing for specific lambdas (e.g. equality). For example, a substring search using equality for characters could use bitwise comparison. Andrei

I think this is better handled by a library solution - define standard templated comparators somewhere and have special support for these. There are dozens of ways to write the same comparison in D and allowing equality tests to work in some cases is likely to be as frustrating as string1 == string2 working sometimes in java.
Sep 23 2011
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2011-09-22 23:08, bearophile wrote:
 Andrei Alexandrescu:

 A function literal should be comparable to another for equality.

Are you willing to explain me why, and show an use case? Bye, bearophile

When using lambdas as event handlers: class Foo { event[] events; void registerEventHandler (void delegate (event) dg) { if (!events.contains(dg)) // register a given just delegate once events ~= dg; } } -- /Jacob Carlborg
Sep 22 2011
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 22 Sep 2011 16:54:55 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:


 4. Add this rewrite to the grammar:

 (comma_separated_parms) => expression

 translates to

 (comma_separated_parms) => expression

Am I missing something here? -Steve
Sep 22 2011
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/22/11 4:03 PM, Steven Schveighoffer wrote:
 On Thu, 22 Sep 2011 16:54:55 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:


 4. Add this rewrite to the grammar:

 (comma_separated_parms) => expression

 translates to

 (comma_separated_parms) => expression

Am I missing something here?

I am. The rewrite should be: (comma_separated_parms) { return expression; } Andrei
Sep 22 2011
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/22/2011 2:03 PM, Steven Schveighoffer wrote:
 On Thu, 22 Sep 2011 16:54:55 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:


 4. Add this rewrite to the grammar:

 (comma_separated_parms) => expression

 translates to

 (comma_separated_parms) => expression

Am I missing something here?

I like easy rewrites!
Sep 22 2011
prev sibling next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
I'd much rather see the bugs in the current lambda syntax get fixed (e.g.
http://d.puremagic.com/issues/show_bug.cgi?id=4724) rather than spend more time
bikeshedding.

== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article
 On 9/21/11 5:17 PM, Walter Bright wrote:
 I've collected a few from various languages for comparison:

I think we should do the following: 1. Introduce a new token "=>" 2. Add this rewrite to the grammar: symbol => expression translates to (symbol) { return expression; } 3. Add this rewrite to the grammar: symbol1 symbol2 => expression translates to (symbol1 symbol2) { return expression; } 4. Add this rewrite to the grammar: (comma_separated_parms) => expression translates to (comma_separated_parms) => expression Each item in comma_separated_parms may be 1 or 2 symbols separated by whitespace. Example: (int a, b) => a + b is valid and translates to (int a, b) { return a + b; } 5. The expression cannot contain commas at top level; an unparenthesized comma is considered to finish expression, just like in a function call's argument list. For example: fun(int a => a + 1, a + 2) is interpreted as fun((int a => a + 1), (a + 2)) To use comma inside expression, add parens around it. 5. Remove bugs and limitations. A function literal may specify none, all, or some parameter types, and the compiler correctly figures out the appropriate template and non-template parameters. The literal subsequently converts to function pointer or delegate whenever there's a match of parameter and result types. Andrei

== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article
 On 9/21/11 5:17 PM, Walter Bright wrote:
 I've collected a few from various languages for comparison:

I think we should do the following: 1. Introduce a new token "=>" 2. Add this rewrite to the grammar: symbol => expression translates to (symbol) { return expression; } 3. Add this rewrite to the grammar: symbol1 symbol2 => expression translates to (symbol1 symbol2) { return expression; } 4. Add this rewrite to the grammar: (comma_separated_parms) => expression translates to (comma_separated_parms) => expression Each item in comma_separated_parms may be 1 or 2 symbols separated by whitespace. Example: (int a, b) => a + b is valid and translates to (int a, b) { return a + b; } 5. The expression cannot contain commas at top level; an unparenthesized comma is considered to finish expression, just like in a function call's argument list. For example: fun(int a => a + 1, a + 2) is interpreted as fun((int a => a + 1), (a + 2)) To use comma inside expression, add parens around it. 5. Remove bugs and limitations. A function literal may specify none, all, or some parameter types, and the compiler correctly figures out the appropriate template and non-template parameters. The literal subsequently converts to function pointer or delegate whenever there's a match of parameter and result types. Andrei

== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article
 On 9/21/11 5:17 PM, Walter Bright wrote:
 I've collected a few from various languages for comparison:

I think we should do the following: 1. Introduce a new token "=>" 2. Add this rewrite to the grammar: symbol => expression translates to (symbol) { return expression; } 3. Add this rewrite to the grammar: symbol1 symbol2 => expression translates to (symbol1 symbol2) { return expression; } 4. Add this rewrite to the grammar: (comma_separated_parms) => expression translates to (comma_separated_parms) => expression Each item in comma_separated_parms may be 1 or 2 symbols separated by whitespace. Example: (int a, b) => a + b is valid and translates to (int a, b) { return a + b; } 5. The expression cannot contain commas at top level; an unparenthesized comma is considered to finish expression, just like in a function call's argument list. For example: fun(int a => a + 1, a + 2) is interpreted as fun((int a => a + 1), (a + 2)) To use comma inside expression, add parens around it. 5. Remove bugs and limitations. A function literal may specify none, all, or some parameter types, and the compiler correctly figures out the appropriate template and non-template parameters. The literal subsequently converts to function pointer or delegate whenever there's a match of parameter and result types. Andrei

Sep 22 2011
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/22/11 4:13 PM, dsimcha wrote:
 I'd much rather see the bugs in the current lambda syntax get fixed (e.g.
 http://d.puremagic.com/issues/show_bug.cgi?id=4724) rather than spend more time
 bikeshedding.

That's not an either-or choice, and of course improving current lambdas (btw that's not a purely syntactic bug) would improve the rewrites as well. What I noticed lately is that people simply appreciate terse lambdas a whole lot. They hate C++ lambdas because you need to mention types, dislike Java's poor solution to lambdas to the extent the language had to add a feature just for them (which is subject to further controversy) and so on. I think current D is no slouch for lambda expressions, and function attribute deduction adds great power to lambdas, but further simplifying lambdas may mark a sensible improvement in their usability. Andrei
Sep 22 2011
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, September 22, 2011 14:47 Andrei Alexandrescu wrote:
 On 9/22/11 4:13 PM, dsimcha wrote:
 I'd much rather see the bugs in the current lambda syntax get fixed (e.g.
 http://d.puremagic.com/issues/show_bug.cgi?id=4724) rather than spend
 more time bikeshedding.

That's not an either-or choice, and of course improving current lambdas (btw that's not a purely syntactic bug) would improve the rewrites as well. What I noticed lately is that people simply appreciate terse lambdas a whole lot. They hate C++ lambdas because you need to mention types, dislike Java's poor solution to lambdas to the extent the language had to add a feature just for them (which is subject to further controversy) and so on. I think current D is no slouch for lambda expressions, and function attribute deduction adds great power to lambdas, but further simplifying lambdas may mark a sensible improvement in their usability.

It wouldn't hurt my feelings any if an abbreviated lambda syntax weren't added, but it _is_ a bit annoying that lambdas are as long as they are for simple stuff - especially when I'm forced to use the lambda syntax because the string syntax that I was trying to use wouldn't work for one reason or another. So, adding an abbreviated lambda syntax is likely a good idea. And your suggested syntax is probably the right way to go, since it's most similar to C# rather than one of the functional languages, and none of the other syntaxes are really objectively better anyway. But we will need someone to take the time to implement it (though fortunately, that's far easier now than it used to be given the increasing number of contributors to dmd). - Jonathan M Davis
Sep 22 2011
prev sibling next sibling parent Cristi Cobzarenco <cristi.cobzarenco gmail.com> writes:
---
Cristi Cobzarenco
BSc in Artificial Intelligence and Computer Science
University of Edinburgh
Profile: http://www.google.com/profiles/cristi.cobzarenco



On 22 September 2011 22:03, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 On Thu, 22 Sep 2011 16:54:55 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:


 4. Add this rewrite to the grammar:

 (comma_separated_parms) => expression

 translates to

 (comma_separated_parms) => expression

Am I missing something here? -Steve

Of course he meant (comma_separated_parms) { return expression; }
Sep 22 2011
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2011-09-22 22:54, Andrei Alexandrescu wrote:
 On 9/21/11 5:17 PM, Walter Bright wrote:
 I've collected a few from various languages for comparison:

I think we should do the following: 1. Introduce a new token "=>" 2. Add this rewrite to the grammar: symbol => expression translates to (symbol) { return expression; } 3. Add this rewrite to the grammar: symbol1 symbol2 => expression translates to (symbol1 symbol2) { return expression; } 4. Add this rewrite to the grammar: (comma_separated_parms) => expression translates to (comma_separated_parms) => expression Each item in comma_separated_parms may be 1 or 2 symbols separated by whitespace. Example: (int a, b) => a + b is valid and translates to (int a, b) { return a + b; } 5. The expression cannot contain commas at top level; an unparenthesized comma is considered to finish expression, just like in a function call's argument list. For example: fun(int a => a + 1, a + 2) is interpreted as fun((int a => a + 1), (a + 2)) To use comma inside expression, add parens around it. 5. Remove bugs and limitations. A function literal may specify none, all, or some parameter types, and the compiler correctly figures out the appropriate template and non-template parameters. The literal subsequently converts to function pointer or delegate whenever there's a match of parameter and result types. Andrei

I like it. Just to be clear, when having a parameter list of one parameter, the parentheses are optional; and when having multiple parameters the parentheses are mandatory? Would any of these be allowed: symbol => { expression } // braces, implicit return, no semicolon symbol => { expression; } // if legal, would this return void or expression symbol => expression; // semicolon symbol => { return expression; } // braces, explicit return, semicolon symbol => return expression; // explicit return, semicolon symbol => { expression; expression } // multi-line lambda, braces, implicit return, no semicolon -- /Jacob Carlborg
Sep 22 2011
parent reply travert phare.normalesup.org (Christophe) writes:
Jacob Carlborg , dans le message (digitalmars.D:145083), a écrit :
 On 2011-09-22 22:54, Andrei Alexandrescu wrote:
 On 9/21/11 5:17 PM, Walter Bright wrote:
 I've collected a few from various languages for comparison:

I think we should do the following: 1. Introduce a new token "=>" 2. Add this rewrite to the grammar: symbol => expression translates to (symbol) { return expression; } 3. Add this rewrite to the grammar: symbol1 symbol2 => expression translates to (symbol1 symbol2) { return expression; } 4. Add this rewrite to the grammar: (comma_separated_parms) => expression translates to (comma_separated_parms) => expression Each item in comma_separated_parms may be 1 or 2 symbols separated by whitespace. Example: (int a, b) => a + b is valid and translates to (int a, b) { return a + b; } 5. The expression cannot contain commas at top level; an unparenthesized comma is considered to finish expression, just like in a function call's argument list. For example: fun(int a => a + 1, a + 2) is interpreted as fun((int a => a + 1), (a + 2)) To use comma inside expression, add parens around it. 5. Remove bugs and limitations. A function literal may specify none, all, or some parameter types, and the compiler correctly figures out the appropriate template and non-template parameters. The literal subsequently converts to function pointer or delegate whenever there's a match of parameter and result types. Andrei

I like it. Just to be clear, when having a parameter list of one parameter, the parentheses are optional; and when having multiple parameters the parentheses are mandatory? Would any of these be allowed: symbol => { expression } // braces, implicit return, no semicolon symbol => { expression; } // if legal, would this return void or expression symbol => expression; // semicolon symbol => { return expression; } // braces, explicit return, semicolon symbol => return expression; // explicit return, semicolon symbol => { expression; expression } // multi-line lambda, braces, implicit return, no semicolon

No, we should not kill a good syntax idea by giving ways to abuse it right away. First implement "symbol => expresion" Then see if it works well and if it should benefit from further improvement. BTW, the main improvement is to avoid punctuation and return, so there is no gain to introduce them again. -- Christophe
Sep 23 2011
parent Jacob Carlborg <doob me.com> writes:
On 2011-09-23 10:50, Christophe wrote:
 Jacob Carlborg , dans le message (digitalmars.D:145083), a écrit :
 On 2011-09-22 22:54, Andrei Alexandrescu wrote:
 On 9/21/11 5:17 PM, Walter Bright wrote:
 I've collected a few from various languages for comparison:

I think we should do the following: 1. Introduce a new token "=>" 2. Add this rewrite to the grammar: symbol => expression translates to (symbol) { return expression; } 3. Add this rewrite to the grammar: symbol1 symbol2 => expression translates to (symbol1 symbol2) { return expression; } 4. Add this rewrite to the grammar: (comma_separated_parms) => expression translates to (comma_separated_parms) => expression Each item in comma_separated_parms may be 1 or 2 symbols separated by whitespace. Example: (int a, b) => a + b is valid and translates to (int a, b) { return a + b; } 5. The expression cannot contain commas at top level; an unparenthesized comma is considered to finish expression, just like in a function call's argument list. For example: fun(int a => a + 1, a + 2) is interpreted as fun((int a => a + 1), (a + 2)) To use comma inside expression, add parens around it. 5. Remove bugs and limitations. A function literal may specify none, all, or some parameter types, and the compiler correctly figures out the appropriate template and non-template parameters. The literal subsequently converts to function pointer or delegate whenever there's a match of parameter and result types. Andrei

I like it. Just to be clear, when having a parameter list of one parameter, the parentheses are optional; and when having multiple parameters the parentheses are mandatory? Would any of these be allowed: symbol => { expression } // braces, implicit return, no semicolon symbol => { expression; } // if legal, would this return void or expression symbol => expression; // semicolon symbol => { return expression; } // braces, explicit return, semicolon symbol => return expression; // explicit return, semicolon symbol => { expression; expression } // multi-line lambda, braces, implicit return, no semicolon

No, we should not kill a good syntax idea by giving ways to abuse it right away.

I wouldn't say it's abusing the syntax.
 First implement "symbol =>  expresion"

 Then see if it works well and if it should benefit from further
 improvement.

 BTW, the main improvement is to avoid punctuation and return, so there
 is no gain to introduce them again.

Yeah, I know. -- /Jacob Carlborg
Sep 23 2011
prev sibling next sibling parent reply zeljkog <zeljkog private.com> writes:
While we are about rewrites, it would be nice one:

symbol := expression;  -> auto symbol = expression;

1. shorter
2. conspicuous, more readable.
3. highlights distinction between assignment and initialization.
4. will not break any existing code.
Sep 23 2011
parent travert phare.normalesup.org (Christophe) writes:
zeljkog , dans le message (digitalmars.D:145087), a écrit :
 
 While we are about rewrites, it would be nice one:
 
 symbol := expression;  -> auto symbol = expression;
 
 1. shorter
 2. conspicuous, more readable.
 3. highlights distinction between assignment and initialization.
 4. will not break any existing code.

I quite like it.
Sep 23 2011
prev sibling next sibling parent reply "Martin Nowak" <dawg dawgfoto.de> writes:
On Thu, 22 Sep 2011 22:54:55 +0200, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 9/21/11 5:17 PM, Walter Bright wrote:
 I've collected a few from various languages for comparison:

I think we should do the following: 1. Introduce a new token "=>" 2. Add this rewrite to the grammar: symbol => expression translates to (symbol) { return expression; } 3. Add this rewrite to the grammar: symbol1 symbol2 => expression translates to (symbol1 symbol2) { return expression; } 4. Add this rewrite to the grammar: (comma_separated_parms) => expression translates to (comma_separated_parms) => expression Each item in comma_separated_parms may be 1 or 2 symbols separated by whitespace. Example: (int a, b) => a + b is valid and translates to (int a, b) { return a + b; } 5. The expression cannot contain commas at top level; an unparenthesized comma is considered to finish expression, just like in a function call's argument list. For example: fun(int a => a + 1, a + 2) is interpreted as fun((int a => a + 1), (a + 2)) To use comma inside expression, add parens around it. 5. Remove bugs and limitations. A function literal may specify none, all, or some parameter types, and the compiler correctly figures out the appropriate template and non-template parameters. The literal subsequently converts to function pointer or delegate whenever there's a match of parameter and result types. Andrei

I want to add some points against introducing this particular syntax. 1. Foremost using '=>' is unfamiliar. Comming from C++ or Java you really have to learn reading it. If you weighted the lambda syntaxes with the tiobe factor, arrows would be a minority. How often have you stopped reading about a language because the code examples were unreadable? Besides my liking for haskell, I don't want to see anything close to this on the D site. mergesortBy less [] = [] mergesortBy less xs = head $ until (null.tail) pairs [[x] | x <- xs] where pairs (x:y:t) = merge x y : pairs t pairs xs = xs merge (x:xs) (y:ys) | less y x = y : merge (x:xs) ys | otherwise = x : merge xs (y:ys) merge xs ys = xs ++ ys 2. D is not a functional language, using the implies arrow in 'a => write(1, a.ptr, a.length)' creates a horribly association. 3. I don't see any of the proposed rewrites is working for nullary delegates. '=> foo()' ??? Or '_ => foo()' => 'Error can't deduce parameter'. 4. The expression is badly delimited. The first rewrite symbol => expression is actually symbol => expression\{CommaExpression, CatExpression}. E.g.: dgs ~= (int a) => (a + 5) ~ (int a) => (a ^^ 2); foo(a, b => (log(b), b), c) And that with a pending tuple syntax reclaming even more parens, comma overloads. So D is a curly bracket language. http://en.wikipedia.org/wiki/List_of_programming_languages_by_category#Curly-bracket_languages What is wrong the, I think earlier proposed, very simple solution. http://www.digitalmars.com/d/2.0/expression.html#FunctionLiteral FunctionLiteral: function Typeopt ParameterAttributes opt FunctionLiteralBody delegate Typeopt ParameterAttributes opt FunctionLiteralBody ParameterAttributes FunctionLiteralBody FunctionLiteralBody ParameterAttributes: Parameters Parameters FunctionAttributes FunctionLiteralBody: FunctionBody '{' Expression '}' (a, b) {a+b} // takes the same amount of characters (a, b) {return a+b;} // return is no expression, be explicit () {call()} // nullary dgs ~= (int a){a + 5} ~ (int a){a ^^ 2}; foo(a, (b){log(b), b}, c) You still can use the old variant without totally diverging in syntax. - It is brief - It uses very little syntax changes => less unknown traps martin P.S.: I'm very undecided whether this should apply to functions too. size_t foo() { 6 } P.P.S.: D already seems to have the briefest delegates. http://en.wikipedia.org/wiki/Anonymous_function#Examples P.P.P.S.: One can use a full function body for delegates including contracts. auto dg = delegate uint(int a) in{ assert(a >= 3); } body { return a - 3; };
Sep 23 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/23/11 8:03 PM, Martin Nowak wrote:
 On Thu, 22 Sep 2011 22:54:55 +0200, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 I want to add some points against introducing this particular syntax.

 1. Foremost using '=>' is unfamiliar. Comming from C++ or Java you
 really have to learn reading it.
 If you weighted the lambda syntaxes with the tiobe factor, arrows would
 be a minority.

Well the C++2011 lambda syntax is quite foreign for C++ users, too.
 How often have you stopped reading about a language because the code
 examples were unreadable?
 Besides my liking for haskell, I don't want to see anything close to
 this on the D site.

 mergesortBy less [] = []
 mergesortBy less xs = head $ until (null.tail) pairs [[x] | x <- xs]
 where
 pairs (x:y:t) = merge x y : pairs t
 pairs xs = xs
 merge (x:xs) (y:ys) | less y x = y : merge (x:xs) ys
 | otherwise = x : merge xs (y:ys)
 merge xs ys = xs ++ ys

I don't understand the point being made here.
 2. D is not a functional language, using the implies arrow in 'a =>
 write(1, a.ptr, a.length)' creates a horribly association.

Hackeyed as that sounds, D is a multi-paradigm language and includes a lot of functional artifacts.
 3. I don't see any of the proposed rewrites is working for nullary
 delegates.
 '=> foo()' ???
 Or '_ => foo()' => 'Error can't deduce parameter'.

The comma-separated list may be empty.
 4. The expression is badly delimited.
 The first rewrite symbol => expression
 is actually symbol => expression\{CommaExpression, CatExpression}.

 E.g.:
 dgs ~= (int a) => (a + 5) ~ (int a) => (a ^^ 2);
 foo(a, b => (log(b), b), c)
 And that with a pending tuple syntax reclaming even more parens, comma
 overloads.

Not sure I understand this point either, sorry.
 So D is a curly bracket language.
 http://en.wikipedia.org/wiki/List_of_programming_languages_by_category#Curly-bracket_languages

 What is wrong the, I think earlier proposed, very simple solution.

 http://www.digitalmars.com/d/2.0/expression.html#FunctionLiteral

 FunctionLiteral:
 function Typeopt ParameterAttributes opt FunctionLiteralBody
 delegate Typeopt ParameterAttributes opt FunctionLiteralBody
 ParameterAttributes FunctionLiteralBody
 FunctionLiteralBody

 ParameterAttributes:
 Parameters
 Parameters FunctionAttributes

 FunctionLiteralBody:
 FunctionBody
 '{' Expression '}'

 (a, b) {a+b} // takes the same amount of characters

We've been discussing the issues of this form. Andrei
Sep 23 2011
next sibling parent John Chapman <john ch.com> writes:
== Quote from Jonathan M Davis (jmdavisProg gmx.com)'s article
 On Friday, September 23, 2011 23:42:52 Andrei Alexandrescu wrote:
 On 9/23/11 8:03 PM, Martin Nowak wrote:
 On Thu, 22 Sep 2011 22:54:55 +0200, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 I want to add some points against introducing this particular syntax.

 1. Foremost using '=>' is unfamiliar. Comming from C++ or Java you
 really have to learn reading it.
 If you weighted the lambda syntaxes with the tiobe factor, arrows would
 be a minority.

Well the C++2011 lambda syntax is quite foreign for C++ users, too.

_is_ a syntax familiar to some of the programmers who use a major language derived from C++. It's certainly going to be more familiar than the syntax of any of the functional languages out there.

Java's adopting the C# syntax for its lambdas too. http://java.dzone.com/news/java-8-lambda-syntax-decided And is it that hard to learn?
Sep 24 2011
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2011-09-24 06:51, Jonathan M Davis wrote:
 On Friday, September 23, 2011 23:42:52 Andrei Alexandrescu wrote:
 On 9/23/11 8:03 PM, Martin Nowak wrote:
 On Thu, 22 Sep 2011 22:54:55 +0200, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org>  wrote:
 I want to add some points against introducing this particular syntax.

 1. Foremost using '=>' is unfamiliar. Comming from C++ or Java you
 really have to learn reading it.
 If you weighted the lambda syntaxes with the tiobe factor, arrows would
 be a minority.

Well the C++2011 lambda syntax is quite foreign for C++ users, too.

And Andrei's suggested syntax is very similar to C#'s lambda syntax, so it _is_ a syntax familiar to some of the programmers who use a major language derived from C++. It's certainly going to be more familiar than the syntax of any of the functional languages out there.

Scala uses the same syntax as well.
 My personal take on it is that if we want more compact lambdas, Andrei's
 proposal gets them about as compact as they can be, and it's similar to C#
 rather than one of the functional languages, so it's more likely to be
 familiar to more D programmers (based on the assumption that D programmers are
 more likely to have programmed in C# than any of the functional languages, or
 at least that D programmers are more likely to be intimately familiar with C#
 than any of the functional languages). So, it's probably the best that we're
 going to get for a compact lambda syntax. The only question is whether we
 really want to add a more compact lambda syntax, and I think that there's
 enough desire for it that we do.

 - Jonathan M Davis

-- /Jacob Carlborg
Sep 24 2011
prev sibling parent travert phare.normalesup.org (Christophe) writes:
"Martin Nowak" , dans le message (digitalmars.D:145287), a écrit :
 4. The expression is badly delimited.
 The first rewrite symbol => expression
 is actually symbol => expression\{CommaExpression, CatExpression}.

 E.g.:
 dgs ~= (int a) => (a + 5) ~ (int a) => (a ^^ 2);



this is a compile time error, because you are appending an int (a+5) with a delegate ((int a) => (a^^2)). You should write : dgs ~= [(int a) => a + 5), ((int a) => a ^^ 2)];
 foo(a, b => (log(b), b), c)



 sort!((a, b) => a <= b)(input)
 vs.
 sort!((a, b) { a <= b })(input)

 
 static assert ((a, b) => a < b != (a, b) => a > b)

That is a compile time error too, because you use != on a boolean on one side, and on a delegate on the other side. You have to use parenthesis arround the delegates to use an operator on them, otherwise the operator could be a part of the delegate. static assert (((a, b) => a < b) != ((a, b) => a > b))
 vs.
 static assert ((a, b) {a < b} != (a, b) {a > b})

 Another minor issue:
 a =>
    a + 3
 Offers worse indentation for long expressions than
 (a) {
    a + 3
 }

 We won't remove the existing function literal syntax due to code breakage.
 We won't remove the string predicates because they are still shorter.
 I am worried about having three subtly different language constructs for  
 the same concept.
 
      (a, b) { return a < b; } |      q{a < b}     | (a, b) => a < b
         | old delegate syntax | string predicates | fat arrow delegates
         |--------------------------------------------------------------
 scope  |    declaration      |   instantiation   |   declaration
 return |    explicit         |   implicit        |   implicit
 body   |    statements       |   expression      |   expression
 types  |    optional         |   no              |   optional
 

Don't forget the return-omissing delegate syntax (a, b) { a < b } :P Old delegate should be kept as the normal way to build a delegate. They are needed to make more than one-liners. Maybe optional types might be removed in the long term to make the language simpler, but they can't be removed. In the long term (D>=3.0, not to break existing code), I am not sure it is worth keeping string predicates if delegates offer a convenient syntax. Moreover they are not a langage feature, they are a library feature. Nothing prevents people from writing a dozen syntax like that. -- Christophe
Sep 27 2011
prev sibling next sibling parent Peter Alexander <peter.alexander.au gmail.com> writes:
On 24/09/11 2:03 AM, Martin Nowak wrote:
 I want to add some points against introducing this particular syntax.

 1. Foremost using '=>' is unfamiliar. Comming from C++ or Java you
 really have to learn reading it.
 If you weighted the lambda syntaxes with the tiobe factor, arrows would
 be a minority.

Just wanted to jump in here and mention that Java is probably going to adopt this syntax for Java 8 lambdas. http://mail.openjdk.java.net/pipermail/lambda-dev/2011-September/003936.html Make of that what you will.
Sep 24 2011
prev sibling parent travert phare.normalesup.org (Christophe) writes:
"Martin Nowak" , dans le message (digitalmars.D:145209), a écrit :
 2. D is not a functional language, using the implies arrow in 'a =>  
 write(1, a.ptr, a.length)' creates a horribly association.

I may repeat myself, but I think -> is a better symbol than =>. => is not just a mistyped comparison operator, it is also, like Martin say, the imply arrow in mathematical language. -> looks like mathematical function notation http://en.wikipedia.org/wiki/Function_%28mathematics%29#Notation although strictly speaking it should be |-> (but that one is horrible). I like both => / -> and (){} notations, both having advantages and inconvenients. -- Christophe
Sep 27 2011
prev sibling next sibling parent reply Alix Pexton <alix.DOT.pexton gmail.DOT.com> writes:
What are the pros and cons of using "=>" rather than "->"?

In an ideal world we might be able to use the correct "rightwards arrow 
from bar" character (u+21A6), but I'm not suggesting we try to make one 
out of the characters we can type ("|->" looks terrible).

To my mind, "->" is somewhat closer to being mathematically correct, 
while "=>" reads as "implies", which is probably why lambdas in other 
languages have confused me.

Is there a lexical justification for choosing "=>" over "->"?

A...
Sep 24 2011
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/24/2011 01:24 PM, Alix Pexton wrote:
 What are the pros and cons of using "=>" rather than "->"?

 In an ideal world we might be able to use the correct "rightwards arrow
 from bar" character (u+21A6), but I'm not suggesting we try to make one
 out of the characters we can type ("|->" looks terrible).

 To my mind, "->" is somewhat closer to being mathematically correct,
 while "=>" reads as "implies", which is probably why lambdas in other
 languages have confused me.

 Is there a lexical justification for choosing "=>" over "->"?

 A...

Both would work, but => and -> both can read as "implies", in which case => is a semantic implication (a statement that the implication is true) and -> is a mere binary boolean operator. (in languages that have this operator, it can be very useful for formulating assertions)
Sep 24 2011
prev sibling next sibling parent "Martin Nowak" <dawg dawgfoto.de> writes:
On Sat, 24 Sep 2011 06:42:52 +0200, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 9/23/11 8:03 PM, Martin Nowak wrote:
 On Thu, 22 Sep 2011 22:54:55 +0200, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 I want to add some points against introducing this particular syntax.

 1. Foremost using '=>' is unfamiliar. Comming from C++ or Java you
 really have to learn reading it.
 If you weighted the lambda syntaxes with the tiobe factor, arrows would
 be a minority.

Well the C++2011 lambda syntax is quite foreign for C++ users, too.
 How often have you stopped reading about a language because the code
 examples were unreadable?
 Besides my liking for haskell, I don't want to see anything close to
 this on the D site.

 mergesortBy less [] = []
 mergesortBy less xs = head $ until (null.tail) pairs [[x] | x <- xs]
 where
 pairs (x:y:t) = merge x y : pairs t
 pairs xs = xs
 merge (x:xs) (y:ys) | less y x = y : merge (x:xs) ys
 | otherwise = x : merge xs (y:ys)
 merge xs ys = xs ++ ys

I don't understand the point being made here.
 2. D is not a functional language, using the implies arrow in 'a =>
 write(1, a.ptr, a.length)' creates a horribly association.

Hackeyed as that sounds, D is a multi-paradigm language and includes a lot of functional artifacts.
 3. I don't see any of the proposed rewrites is working for nullary
 delegates.
 '=> foo()' ???
 Or '_ => foo()' => 'Error can't deduce parameter'.

The comma-separated list may be empty.
 4. The expression is badly delimited.
 The first rewrite symbol => expression
 is actually symbol => expression\{CommaExpression, CatExpression}.

 E.g.:
 dgs ~= (int a) => (a + 5) ~ (int a) => (a ^^ 2);
 foo(a, b => (log(b), b), c)
 And that with a pending tuple syntax reclaming even more parens, comma
 overloads.

Not sure I understand this point either, sorry.

=> looks like an infix operator. It harder to distinguish in a parameter list. The trailing right curly OTOH always ends a function. It makes it visually distinct and is highlighted/matchable in an ide. It prevents interaction of operators with the inner expression. sort!((a, b) => a <= b)(input) vs. sort!((a, b) { a <= b })(input) static assert ((a, b) => a < b != (a, b) => a > b) vs. static assert ((a, b) {a < b} != (a, b) {a > b}) Another minor issue: a => a + 3 Offers worse indentation for long expressions than (a) { a + 3 }
 So D is a curly bracket language.
 http://en.wikipedia.org/wiki/List_of_programming_languages_by_category#Curly-bracket_languages

 What is wrong the, I think earlier proposed, very simple solution.

 http://www.digitalmars.com/d/2.0/expression.html#FunctionLiteral

 FunctionLiteral:
 function Typeopt ParameterAttributes opt FunctionLiteralBody
 delegate Typeopt ParameterAttributes opt FunctionLiteralBody
 ParameterAttributes FunctionLiteralBody
 FunctionLiteralBody

 ParameterAttributes:
 Parameters
 Parameters FunctionAttributes

 FunctionLiteralBody:
 FunctionBody
 '{' Expression '}'

 (a, b) {a+b} // takes the same amount of characters

We've been discussing the issues of this form. Andrei

I've only found one argument being made for this.
 2. What if the lambda wants to actually evaluate the expression but  
 return void?
  3. How is the semicolon relevant? (If its presence is used as a  
 disambiguator for (2), it's poor design to predicate a large semantic  
 difference on such a distinction.)

It will error when you want to use the return value of the delegate. It will error when the expression has no side-effect. It allows to easily create a void return delegate. We already have implicit return for our second lambda syntax q{a+b}. Having both (a, b) { foo(a, b); } and (a, b) => foo(a, b) for such similar constructs is no good design either. C#, Scala and apparently Java8 all allow curly embraced statement blocks after the fat arrow. Scala has an implicit return for this '() => { count += 1; count }'. Will we allow statements () => { return 5; }? We won't remove the existing function literal syntax due to code breakage. We won't remove the string predicates because they are still shorter. I am worried about having three subtly different language constructs for the same concept. (a, b) { return a < b; } | q{a < b} | (a, b) => a < b | old delegate syntax | string predicates | fat arrow delegates |-------------------------------------------------------------- scope | declaration | instantiation | declaration return | explicit | implicit | implicit body | statements | expression | expression types | optional | no | optional martin
Sep 24 2011
prev sibling next sibling parent reply Mafi <mafi example.org> writes:
Am 22.09.2011 22:54, schrieb Andrei Alexandrescu:
 On 9/21/11 5:17 PM, Walter Bright wrote:
 I've collected a few from various languages for comparison:

I think we should do the following: 1. Introduce a new token "=>" 2. Add this rewrite to the grammar: symbol => expression translates to (symbol) { return expression; } 3. Add this rewrite to the grammar: symbol1 symbol2 => expression translates to (symbol1 symbol2) { return expression; } 4. Add this rewrite to the grammar: (comma_separated_parms) => expression translates to (comma_separated_parms) => expression Each item in comma_separated_parms may be 1 or 2 symbols separated by whitespace. Example: (int a, b) => a + b is valid and translates to (int a, b) { return a + b; } 5. The expression cannot contain commas at top level; an unparenthesized comma is considered to finish expression, just like in a function call's argument list. For example: fun(int a => a + 1, a + 2) is interpreted as fun((int a => a + 1), (a + 2)) To use comma inside expression, add parens around it. 5. Remove bugs and limitations. A function literal may specify none, all, or some parameter types, and the compiler correctly figures out the appropriate template and non-template parameters. The literal subsequently converts to function pointer or delegate whenever there's a match of parameter and result types. Andrei

If we decide to add something like this, the => 'operator' has in my opinion to have a higher precidence thand ! or you should be able to write it at least without parenthesis (using other parser tricks). Like this: map!x=>x+1(list) Mafi
Sep 25 2011
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/25/2011 11:43 AM, Mafi wrote:
 Am 22.09.2011 22:54, schrieb Andrei Alexandrescu:
 On 9/21/11 5:17 PM, Walter Bright wrote:
 I've collected a few from various languages for comparison:

I think we should do the following: 1. Introduce a new token "=>" 2. Add this rewrite to the grammar: symbol => expression translates to (symbol) { return expression; } 3. Add this rewrite to the grammar: symbol1 symbol2 => expression translates to (symbol1 symbol2) { return expression; } 4. Add this rewrite to the grammar: (comma_separated_parms) => expression translates to (comma_separated_parms) => expression Each item in comma_separated_parms may be 1 or 2 symbols separated by whitespace. Example: (int a, b) => a + b is valid and translates to (int a, b) { return a + b; } 5. The expression cannot contain commas at top level; an unparenthesized comma is considered to finish expression, just like in a function call's argument list. For example: fun(int a => a + 1, a + 2) is interpreted as fun((int a => a + 1), (a + 2)) To use comma inside expression, add parens around it. 5. Remove bugs and limitations. A function literal may specify none, all, or some parameter types, and the compiler correctly figures out the appropriate template and non-template parameters. The literal subsequently converts to function pointer or delegate whenever there's a match of parameter and result types. Andrei

If we decide to add something like this, the => 'operator' has in my opinion to have a higher precidence thand ! or you should be able to write it at least without parenthesis (using other parser tricks). Like this: map!x=>x+1(list)

It cannot have higher precedence than !, because then your example would be parsed as (map!(x=>x))+(1(list)) Other parser tricks are impossible, because: map!(x=>x+y(list)) and map!(x=>x+y)(list) cannot be distinguished without parens.
Sep 25 2011
prev sibling parent reply Caligo <iteronvexor gmail.com> writes:
--bcaec51b1f678c23c004ae0b274f
Content-Type: text/plain; charset=ISO-8859-1

Is there a reason why a new syntax is needed for anonymous function?  Can we
get the current one working and then worry about making things pretty? C++
anonymous function may not be any better, but it works, and that's in an
experimental implementation (GCC 4.6).

--bcaec51b1f678c23c004ae0b274f
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

Is there a reason why a new syntax is needed for=A0anonymous=A0function? =
=A0Can we get the current one working and then worry about making things=A0=
pretty? C++ anonymous function may not be any better, but it works, and tha=
t&#39;s in an experimental implementation (GCC 4.6).

--bcaec51b1f678c23c004ae0b274f--
Sep 28 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Caligo:

 C++ anonymous function may not be any better, but it works, and that's in an
experimental implementation (GCC 4.6).

In my not humble opinion C++0x lambdas are over-engineered (but they go along with the rest of the language). Bye, bearophile
Sep 28 2011
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
std.algorithm already introduces a sort of lambda syntax...
map!"a+b"(...) or map!q{a+b}(...)

If D is looking for its own style of short lambda, maybe implicit use of a and
b could be extended.
Candidates:
a+b
{a+b}
f{a+b}
auto{a+b}
auto a+b

Personally, I like the 2nd or 3rd one. The second is visually cleaner while the
3rd is easily parsed and feels very similar to q strings. I picked f because
that's frequently used to represent a function. x could work, but that's a
common variable name...

Walter Bright Wrote:

 I've collected a few from various languages for comparison:
 
 D
      (a,b) { return a + b; }
 
 Ruby
      ->(a,b) { a + b }
 
 C++0x
      [](int a, int b) { return a + b; }
 
 C#
      (a,b) => a + b
 
 Scala
      (a:Int, b:Int) => a + b
 
 Erlang
      fun(a, b) -> a + b end.
 
 Haskell
      \a b -> a + b
 
 Javascript
      function(a,b) { return a + b; }
 
 Clojure
      # (+ % %2)
 
 Lua
      function(a,b) return a + b end
 
 Python
      lambda a,b: a + b
 

Sep 22 2011
next sibling parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 22 Sep 2011 18:59:31 -0400, Jason House <jason.james.house gmail.com>
wrote:

 std.algorithm already introduces a sort of lambda syntax...
 map!"a+b"(...) or map!q{a+b}(...)

 If D is looking for its own style of short lambda, maybe implicit use of a and
b could be extended.
 Candidates:
 a+b
 {a+b}
 f{a+b}
 auto{a+b}
 auto a+b

 Personally, I like the 2nd or 3rd one. The second is visually cleaner while
the 3rd is easily parsed and feels very similar to q strings. I picked f
because that's frequently used to represent a function. x could work, but
that's a common variable name...

I like the idea, although 1,2,3 and 5 are too close to valid D syntax for my comfort. We could borrow from Haskell: \{a+b} But I'd prefer not to have special syntax rules inside lambda blocks. (It increases the cognitive load of D) So why not make it a statement? i.e. \a+b; then {} would only be for multi-statement or void functions: \{a+b; return;} What I worry about though is variable hijacking rules. e.g. auto b = 5; reduce!\a+b(map!\a+b([1,2,3,4));
Sep 22 2011
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Robert Jacques:

 What I worry about though is variable hijacking rules. e.g.
 
 auto b = 5;
 reduce!\a+b(map!\a+b([1,2,3,4));

Right, it's a bit too much magical and inflexible for my taste. bye, bearophile
Sep 22 2011
prev sibling parent reply "Alex_Dovhal" <alex_dovhal yahoo.com> writes:
"Robert Jacques" <sandford jhu.edu> wrote
 What I worry about though is variable hijacking rules. e.g.

 auto b = 5;
 reduce!\a+b(map!\a+b([1,2,3,4));

Nice. What if we extend your proposal to \(comma_separated_params)simple_expression \(comma_separated_params){expressions} Then no variable hijacking would be auto b = 5; reduce!\(a)a+b(map!\(x)x+b([1,2,3,4)); reduce!\a+b(map!\a+b([1,2,3,4)); //error, shadowing b
Sep 23 2011
next sibling parent "Alex_Dovhal" <alex_dovhal yahoo.com> writes:
"Alex_Dovhal" <alex_dovhal yahoo.com> wrote
 reduce!\(a)a+b(map!\(x)x+b([1,2,3,4));

Sorry, my mistake reduce!\(a,b)a+b(map!\(x)x+b([1,2,3,4));
Sep 23 2011
prev sibling parent "Alex_Dovhal" <alex_dovhal yahoo.com> writes:
"Robert Jacques" <sandford jhu.edu> wrote
 Well, actually, this is Jason's proposal and it's explicitly for a 
 std.algorithm style, by convention, super-short lambda syntax. i.e. 
 primarily for one liners and std.algorithm. If you go the 
 comma_separated_params, then I think the a => a+x; route is better.

Maybe, x=>f(x) syntax isn't bad, but in most simple and most oftern cases -- \a*a is 4 chars while a=>a*a is 6 chars. Then \(x,y)x+y is 9 chars, (x,y)=>x+y is 10 chars, while \a+b is still 4 chars.
 Actually, I made a error in my final example as each lambda must be 
 terminated somehow. i.e. with a semi-colon:

 reduce!\a+b;(map!\a+b;([1,2,3,4))

No. Those semicolons in the middle of expression looks strange. Compiler can't determine that expression following ! has ended so you must use !() int b = 5; reduce!(\(a,b)a+b)(map!(\(a)a+b)([1, 2, 3, 4]))
 As for hijacking, I think by-convention lambdas should be disallowed if a 
 or b are used in the lambda and are already defined in the namespace. In 
 those cases, you'd have to revert to a more general syntax, i.e.

 reduce!"a+b"(map!(a => a+b)([1,2,3,4)));

In such not often cases one can even use long lambdas reduce!"a+b"(map!((int a){return a+b;})([1,2,3,4]))); BTW, existing usage of strings ("a+b") is second shortest afrer \a+b and is properly delimited. maybe allowing several variations of \lambdas (1) \a+b - automatic names, shortest lambda possible, easy to read. for use when it can be easily delimited e.g list_comprehent!(\a*a, \a!=1)(a) (2) \{a+b} - automatic names, to properly delimit lambda, usefil in map!\{a*a}(a), eh, you are rigth here compiler can omit ! -- map\{a*a}(a) (3) \(x)x+a -- explicit names, to prevent name hijacking. (4) \(x){x+a} - explicit names and properly delimited in (1) and (3) no comma allowed, as it can cause ambiguities.
Sep 24 2011
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Fri, 23 Sep 2011 03:03:04 -0400, Alex_Dovhal <alex_dovhal yahoo.com> wrote:

 "Robert Jacques" <sandford jhu.edu> wrote
 What I worry about though is variable hijacking rules. e.g.

 auto b = 5;
 reduce!\a+b(map!\a+b([1,2,3,4));

Nice. What if we extend your proposal to \(comma_separated_params)simple_expression \(comma_separated_params){expressions} Then no variable hijacking would be auto b = 5; reduce!\(a)a+b(map!\(x)x+b([1,2,3,4)); reduce!\a+b(map!\a+b([1,2,3,4)); //error, shadowing b

Well, actually, this is Jason's proposal and it's explicitly for a std.algorithm style, by convention, super-short lambda syntax. i.e. primarily for one liners and std.algorithm. If you go the comma_separated_params, then I think the a => a+x; route is better. Actually, I made a error in my final example as each lambda must be terminated somehow. i.e. with a semi-colon: reduce!\a+b;(map!\a+b;([1,2,3,4)) Also, you could consider !\ to be a bit redundent and allow 'symbol\statement' to be lowered to 'symbol!\statement'. Thus the following would also be valid: reduce\a+b;(map\a+b;([1,2,3,4)); As for hijacking, I think by-convention lambdas should be disallowed if a or b are used in the lambda and are already defined in the namespace. In those cases, you'd have to revert to a more general syntax, i.e. reduce!"a+b"(map!(a => a+b)([1,2,3,4)));
Sep 23 2011
prev sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Sat, 24 Sep 2011 03:23:13 -0400, Alex_Dovhal <alex_dovhal yahoo.com> wrote:

 "Robert Jacques" <sandford jhu.edu> wrote
 Well, actually, this is Jason's proposal and it's explicitly for a
 std.algorithm style, by convention, super-short lambda syntax. i.e.
 primarily for one liners and std.algorithm. If you go the
 comma_separated_params, then I think the a => a+x; route is better.

Maybe, x=>f(x) syntax isn't bad, but in most simple and most oftern cases -- \a*a is 4 chars while a=>a*a is 6 chars. Then \(x,y)x+y is 9 chars, (x,y)=>x+y is 10 chars, while \a+b is still 4 chars.

I'm not sure you understand the main point: there are multiple ways to define a lambda. So \a+b and (a,b)=>a+b could co-exist together just fine.
 Actually, I made a error in my final example as each lambda must be
 terminated somehow. i.e. with a semi-colon:

 reduce!\a+b;(map!\a+b;([1,2,3,4))

No. Those semicolons in the middle of expression looks strange. Compiler can't determine that expression following ! has ended so you must use !()

How is !() different from !\; ? \; is for literals. Hence, it would work just like !"a+b".
  int b =  5;
  reduce!(\(a,b)a+b)(map!(\(a)a+b)([1, 2, 3, 4]))

 As for hijacking, I think by-convention lambdas should be disallowed if a
 or b are used in the lambda and are already defined in the namespace. In
 those cases, you'd have to revert to a more general syntax, i.e.

 reduce!"a+b"(map!(a => a+b)([1,2,3,4)));

In such not often cases one can even use long lambdas reduce!"a+b"(map!((int a){return a+b;})([1,2,3,4])));

Which is what I was suggesting, although I used the most concise syntax: a => a+b Also, as non-trivial use of algorithm often results in 120+ line widths, today using the "a+b" style syntax, conciseness is golden.
 BTW, existing usage of strings ("a+b") is second shortest afrer \a+b and is
 properly delimited.
 maybe allowing several variations of  \lambdas
 (1) \a+b - automatic names, shortest lambda possible, easy to read. for use
 when it can be easily delimited e.g  list_comprehent!(\a*a, \a!=1)(a)
 (2) \{a+b} - automatic names, to properly delimit lambda, usefil in
 map!\{a*a}(a), eh, you are rigth here compiler can omit ! -- map\{a*a}(a)
 (3) \(x)x+a -- explicit names, to prevent name hijacking.
 (4) \(x){x+a} - explicit names and properly delimited
 in (1) and (3) no comma allowed, as it can cause ambiguities.

Sep 24 2011
prev sibling next sibling parent hhaammaadd <h.battel hotmail.com> writes:
On 09/22/2011 01:17 AM, Walter Bright wrote:
 I've collected a few from various languages for comparison:

 D
 (a,b) { return a + b; }

I prefer to make "return" optional as the argument type
Sep 22 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, September 23, 2011 23:42:52 Andrei Alexandrescu wrote:
 On 9/23/11 8:03 PM, Martin Nowak wrote:
 On Thu, 22 Sep 2011 22:54:55 +0200, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 I want to add some points against introducing this particular syntax.
 
 1. Foremost using '=>' is unfamiliar. Comming from C++ or Java you
 really have to learn reading it.
 If you weighted the lambda syntaxes with the tiobe factor, arrows would
 be a minority.

Well the C++2011 lambda syntax is quite foreign for C++ users, too.

And Andrei's suggested syntax is very similar to C#'s lambda syntax, so it _is_ a syntax familiar to some of the programmers who use a major language derived from C++. It's certainly going to be more familiar than the syntax of any of the functional languages out there. My personal take on it is that if we want more compact lambdas, Andrei's proposal gets them about as compact as they can be, and it's similar to C# rather than one of the functional languages, so it's more likely to be familiar to more D programmers (based on the assumption that D programmers are more likely to have programmed in C# than any of the functional languages, or at least that D programmers are more likely to be intimately familiar with C# than any of the functional languages). So, it's probably the best that we're going to get for a compact lambda syntax. The only question is whether we really want to add a more compact lambda syntax, and I think that there's enough desire for it that we do. - Jonathan M Davis
Sep 23 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, September 24, 2011 07:14:13 John Chapman wrote:
 == Quote from Jonathan M Davis (jmdavisProg gmx.com)'s article
 
 On Friday, September 23, 2011 23:42:52 Andrei Alexandrescu wrote:
 On 9/23/11 8:03 PM, Martin Nowak wrote:
 On Thu, 22 Sep 2011 22:54:55 +0200, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 I want to add some points against introducing this particular
 syntax.
 
 1. Foremost using '=>' is unfamiliar. Comming from C++ or Java
 you
 really have to learn reading it.
 If you weighted the lambda syntaxes with the tiobe factor,
 arrows would be a minority.

Well the C++2011 lambda syntax is quite foreign for C++ users, too.

And Andrei's suggested syntax is very similar to C#'s lambda syntax, so it _is_ a syntax familiar to some of the programmers who use a major language derived from C++. It's certainly going to be more familiar than the syntax of any of the functional languages out there.

Java's adopting the C# syntax for its lambdas too. http://java.dzone.com/news/java-8-lambda-syntax-decided And is it that hard to learn?

I definitely agree with the reasoning given in the article: "Despite extensive searching, there was no clear winner among the alternatives (each form had some good aspects and some really not very good aspects, and there was no form that was clearly better than the others). So, we felt that it was better to choose something that has already been shown to work well in the two languages that are most like Java -- C# and Scala -- rather than to invent something new." It's pretty much my thoughts exactly. So, unless there's something objectively wrong with this syntax which would make it a bad choice for D, I think that we should adopt some version of it. When 2 of the other major C++-derived languages choose a syntax which also works for D, it just seems like a good idea to follow suit. - Jonathan M Davis
Sep 24 2011
prev sibling parent Alvaro <alvaro.segura gmail.com> writes:
El 22/09/2011 0:17, Walter Bright escribi:
 I've collected a few from various languages for comparison:

 D
 (a,b) { return a + b; }

 Ruby
 ->(a,b) { a + b }

 C++0x
 [](int a, int b) { return a + b; }

 C#
 (a,b) => a + b

 Scala
 (a:Int, b:Int) => a + b

 Erlang
 fun(a, b) -> a + b end.

 Haskell
 \a b -> a + b

 Javascript
 function(a,b) { return a + b; }

 Clojure
 # (+ % %2)

 Lua
 function(a,b) return a + b end

 Python
 lambda a,b: a + b

Just for the record, Vala also uses (a, b) => a + b no curly braces needed if only one statement, and no argument types. http://live.gnome.org/Vala/Tutorial#Delegates BTW, al least superficially, Vala reminds me of D quite a lot.
Sep 24 2011