www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Lambda syntax, etc

reply bearophile <bearophileHUGS lycos.com> writes:
I've taken a look at the syntax for lambda in other C-like languages.
This is from Functional Java:
http://functionaljava.org/examples#Array.filter

In Functional Java you can write this D syntax:
(int i, int j) { return i % 3 == j; }
as:
{ int i, int j => i % 3 == j }

It's shorter and less cluttered/noisy than the D syntax, and it doesn't require
more type inferencing (but I think you can't put statements there, so it's less
powerful).

With that Java syntax extension you can write:

final Array<Integer> a = array(97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64,
6, 79, 42);  
final Array<Integer> b = a.filter({int i => i % 2 == 0});  

In D (with dlibs) it is:

auto a = [97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42];
auto b = a.filter((int i){return !(i % 2);});

With std.algorithm it may be a bit shorter.

In Python:

a = [97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42]
b = [x for x in a if not(i % 2)]


C#2 has lambdas, and C#3 adds closures and more type inferencing, so C#3+
supports the following syntaxes:
(int i) => { return i % 3 == 1; } // C#2
i => i % 3 == 1 // C#3
i => { return i % 3 == 1; } // C#3, with statements too
To define a delegate o delegate closure:
Func<int> foo = i => { return i % 3 == 1; };
Func<int> foo = i => i % 3 == 1;
Func<int> bar = () => 2;
But this isn't allowed:
Func<void> bar = () => 2;


Few comments I have copied relative to C#3:

C# it automatically generates either an anonymous class or an anonymous method
for the closure depending on if the function needs to close over the local
scope or not.<
When such an expression is evaluated, it produces a function-object which can
be called with the arguments implied by the LambdaList, and whose body
expressions have access to all the lexical variables that are visible at that
point. The ones that are outside of the expression, whose bindings were
established before it was created, are captured. This is why the resulting
object is called a LexicalClosure.<
Even when the code uses the closure more than once, the compiler creates only
one instance of the closure. That environment is reused each time.<
Bye, bearophile
Feb 04 2009
next sibling parent reply BCS <none anon.com> writes:
Hello bearophile,

 I've taken a look at the syntax for lambda in other C-like languages.
 This is from Functional Java:
 http://functionaljava.org/examples#Array.filter
 
 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j => i % 3 == j }
That syntax, and a few of the below, show the one major gripe I have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition. [...]
 i => i % 3 == 1 // C#3
 
 i => { return i % 3 == 1; } // C#3, with statements too
 
 To define a delegate o delegate closure:
 
 Func<int> foo = i => { return i % 3 == 1; };
 
 Func<int> foo = i => i % 3 == 1;
 
 Func<int> bar = () => 2;
 
Feb 04 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
BCS wrote:
 Hello bearophile,
 
 I've taken a look at the syntax for lambda in other C-like languages.
 This is from Functional Java:
 http://functionaljava.org/examples#Array.filter

 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j => i % 3 == j }
That syntax, and a few of the below, show the one major gripe I have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition.
Strings are immune from the problem. :o) Also they make for readily recognizable code because they all use the same argument names. Andrei
Feb 04 2009
next sibling parent "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:gmclr4$2q30$1 digitalmars.com...
 BCS wrote:
 Hello bearophile,

 I've taken a look at the syntax for lambda in other C-like languages.
 This is from Functional Java:
 http://functionaljava.org/examples#Array.filter

 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j => i % 3 == j }
That syntax, and a few of the below, show the one major gripe I have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition.
Strings are immune from the problem. :o) Also they make for readily recognizable code because they all use the same argument names. Andrei
I would be all for the string-style, *if* things like the following were fixed: int foo1(int i) { /*stuff*/ } void bar(int[] ints) { int foo2(int i) { /*stuff*/ } auto x = ints.map!("foo1(a)+foo2(a)")(); }
Feb 04 2009
prev sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
Andrei Alexandrescu wrote:
 BCS wrote:
 Hello bearophile,

 I've taken a look at the syntax for lambda in other C-like languages.
 This is from Functional Java:
 http://functionaljava.org/examples#Array.filter

 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j => i % 3 == j }
That syntax, and a few of the below, show the one major gripe I have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition.
Strings are immune from the problem. :o) Also they make for readily recognizable code because they all use the same argument names. Andrei
Personally I prefer to have syntax for "blocks" like Ruby/smalltalk. given the following example function: int func(int a, delegate int(int) dg) { .. } // call func with [something in this spirit is my favorite]: func(someInt) { | int a, int b | return a+b; }; compare with the current D syntax: func( someInt, (int a, int b) {return a+b;} ); compare with a lamda syntax: func(someInt, { int a, int b => a+b } ); blocks are more useful - they are not limited to just one expression, and I think are a more general construct. lamdas/array comps, are just special cases.
Feb 04 2009
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Yigal Chripun" <yigal100 gmail.com> wrote in message 
news:gmd0u8$fg7$1 digitalmars.com...
 Andrei Alexandrescu wrote:
 BCS wrote:
 Hello bearophile,

 I've taken a look at the syntax for lambda in other C-like languages.
 This is from Functional Java:
 http://functionaljava.org/examples#Array.filter

 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j => i % 3 == j }
That syntax, and a few of the below, show the one major gripe I have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition.
Strings are immune from the problem. :o) Also they make for readily recognizable code because they all use the same argument names. Andrei
Personally I prefer to have syntax for "blocks" like Ruby/smalltalk. given the following example function: int func(int a, delegate int(int) dg) { .. } // call func with [something in this spirit is my favorite]: func(someInt) { | int a, int b | return a+b; }; compare with the current D syntax: func( someInt, (int a, int b) {return a+b;} ); compare with a lamda syntax: func(someInt, { int a, int b => a+b } ); blocks are more useful - they are not limited to just one expression, and I think are a more general construct. lamdas/array comps, are just special cases.
Agreed. This is what I had always been ultimately hoping for. I'd be happy with the string stuff if that "wrong scope" issue gets fixed (that I mentioned in another branch of this thread), but I'd still prefer this (especially if the types for the params could somehow be inferred and omitted like this: "func(someInt) { |a,b| return a+b; };" ) ).
Feb 04 2009
parent reply BCS <ao pathlink.com> writes:
Reply to Nick,

 "Yigal Chripun" <yigal100 gmail.com> wrote in message
 news:gmd0u8$fg7$1 digitalmars.com...
 
 Andrei Alexandrescu wrote:
 
 BCS wrote:
 
 Hello bearophile,
 
 I've taken a look at the syntax for lambda in other C-like
 languages. This is from Functional Java:
 http://functionaljava.org/examples#Array.filter
 
 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j => i % 3 == j }
That syntax, and a few of the below, show the one major gripe I have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition.
Strings are immune from the problem. :o) Also they make for readily recognizable code because they all use the same argument names. Andrei
Personally I prefer to have syntax for "blocks" like Ruby/smalltalk. given the following example function: int func(int a, delegate int(int) dg) { .. } // call func with [something in this spirit is my favorite]: func(someInt) { | int a, int b | return a+b; }; compare with the current D syntax: func( someInt, (int a, int b) {return a+b;} ); compare with a lamda syntax: func(someInt, { int a, int b => a+b } ); blocks are more useful - they are not limited to just one expression, and I think are a more general construct. lamdas/array comps, are just special cases.
Agreed. This is what I had always been ultimately hoping for. I'd be happy with the string stuff if that "wrong scope" issue gets fixed (that I mentioned in another branch of this thread), but I'd still prefer this (especially if the types for the params could somehow be inferred and omitted like this: ) ).
Why use this: "func(someInt) { |a,b| return a+b; };" when you can reuse syntax and get this for the same amount of typeing "func(someInt) (a,b){ return a+b; };"
Feb 04 2009
next sibling parent reply Bill Baxter <wbaxter gmail.com> writes:
On Thu, Feb 5, 2009 at 7:26 AM, BCS <ao pathlink.com> wrote:
 Reply to Nick,

 "Yigal Chripun" <yigal100 gmail.com> wrote in message
 news:gmd0u8$fg7$1 digitalmars.com...

 Andrei Alexandrescu wrote:

 BCS wrote:

 Hello bearophile,

 I've taken a look at the syntax for lambda in other C-like
 languages. This is from Functional Java:
 http://functionaljava.org/examples#Array.filter

 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j => i % 3 == j }
That syntax, and a few of the below, show the one major gripe I have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition.
Strings are immune from the problem. :o) Also they make for readily recognizable code because they all use the same argument names. Andrei
Personally I prefer to have syntax for "blocks" like Ruby/smalltalk. given the following example function: int func(int a, delegate int(int) dg) { .. } // call func with [something in this spirit is my favorite]: func(someInt) { | int a, int b | return a+b; }; compare with the current D syntax: func( someInt, (int a, int b) {return a+b;} ); compare with a lamda syntax: func(someInt, { int a, int b => a+b } ); blocks are more useful - they are not limited to just one expression, and I think are a more general construct. lamdas/array comps, are just special cases.
Agreed. This is what I had always been ultimately hoping for. I'd be happy with the string stuff if that "wrong scope" issue gets fixed (that I mentioned in another branch of this thread), but I'd still prefer this (especially if the types for the params could somehow be inferred and omitted like this: ) ).
Why use this: "func(someInt) { |a,b| return a+b; };" when you can reuse syntax and get this for the same amount of typeing "func(someInt) (a,b){ return a+b; };"
I was about to say the same thing, but I think Yigal was just mixing two distinct suggestions together: 1) the trailing delegates proposal (aka ruby block) and 2) A ruby-like syntax for delegate literals : {|a,b| return a+b;} --bb
Feb 04 2009
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Bill,

 I was about to say the same thing, but I think Yigal was just mixing
two distinct suggestions together: 1) the trailing delegates proposal (aka ruby block) and
I like that
 2) A ruby-like syntax for delegate literals : {|a,b| return a+b;}
I don't like that One #1 I'd be inclined to requier that the function be defined like
 void DoIt(int delegate(int) dg...)
D laready has this syntax for Typesafe Variadic Functions http://www.digitalmars.com/d/1.0/function.html
Feb 04 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"BCS" <ao pathlink.com> wrote in message 
news:78ccfa2d39bdc8cb54edb3210678 news.digitalmars.com...
 Reply to Bill,

 I was about to say the same thing, but I think Yigal was just mixing
two distinct suggestions together: 1) the trailing delegates proposal (aka ruby block) and
I like that
Then we're agreed on that part :)
 2) A ruby-like syntax for delegate literals : {|a,b| return a+b;}
I don't like that
The thing I like about that is that it makes it much more clear at a glance that the "a,b" or "int a, int b" is associated with the code block (but without the problem some languages have of making it hard to distinguish from the block's body). For the sake of syntax-consistency I would be perfectly willing to allow (or even require) functions to be defined the same way: int add { |int x, int y| return x+y; } Or: // "func" used to disambiguate between function call and function declaration func add { |int <- int x, int y | return x+y; } Or maybe parens instead of pipes (this is similar to K&R C, isn't it?): int add { (int x, int y) return x+y; } Although I'm sure any of those would be prohibitively unpopular.
 One #1 I'd be inclined to requier that the function be defined like

 void DoIt(int delegate(int) dg...)
D laready has this syntax for Typesafe Variadic Functions http://www.digitalmars.com/d/1.0/function.html
I'm not quite convinced either way on this. For what reasons do you think the function header should be required to indicate "this uses block syntax"? What's wrong with just saying "If the last arg a function takes is a delegate, then that delegate can optionally be specified with block syntax."?
Feb 04 2009
next sibling parent "Nick Sabalausky" <a a.a> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:gmdtjl$2f4j$1 digitalmars.com...
 // "func" used to disambiguate between function call and function 
 declaration
 func add { |int <- int x, int y |
    return x+y;
 }
This one has the added benefit of making it easy to distinguish between an attribute of the function and an attribute of the function's return value (Although I guess that's not much of an issue with the current versions of D2).
Feb 04 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Thu, Feb 5, 2009 at 2:30 PM, Nick Sabalausky <a a.a> wrote:
 2) A ruby-like syntax for delegate literals : {|a,b| return a+b;}
I don't like that
The thing I like about that is that it makes it much more clear at a glance that the "a,b" or "int a, int b" is associated with the code block (but without the problem some languages have of making it hard to distinguish from the block's body).
I agree. Putting the args inside the { } is much more readable to me too. Even just putting the parens inside rather than outside seems an improvement. Or how about { int x; int y :: return x+y; }
 Or maybe parens instead of pipes (this is similar to K&R C, isn't it?):

 int add { (int x, int y)
    return x+y;
 }
K&R was like int add(x,y) int x; int y; { return x+y } --bb
Feb 04 2009
prev sibling next sibling parent reply Bill Baxter <wbaxter gmail.com> writes:
On Thu, Feb 5, 2009 at 2:56 PM, Bill Baxter <wbaxter gmail.com> wrote:
 On Thu, Feb 5, 2009 at 2:30 PM, Nick Sabalausky <a a.a> wrote:
 2) A ruby-like syntax for delegate literals : {|a,b| return a+b;}
I don't like that
The thing I like about that is that it makes it much more clear at a glance that the "a,b" or "int a, int b" is associated with the code block (but without the problem some languages have of making it hard to distinguish from the block's body).
I agree. Putting the args inside the { } is much more readable to me too. Even just putting the parens inside rather than outside seems an improvement. Or how about { int x; int y :: return x+y; }
Oh, and last semicolon of a function should be optional :-) { int x; int y :: return x+y } --bb
Feb 04 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"Bill Baxter" <wbaxter gmail.com> wrote in message 
news:mailman.651.1233813474.22690.digitalmars-d puremagic.com...
 On Thu, Feb 5, 2009 at 2:56 PM, Bill Baxter <wbaxter gmail.com> wrote:
 On Thu, Feb 5, 2009 at 2:30 PM, Nick Sabalausky <a a.a> wrote:
 2) A ruby-like syntax for delegate literals : {|a,b| return a+b;}
I don't like that
The thing I like about that is that it makes it much more clear at a glance that the "a,b" or "int a, int b" is associated with the code block (but without the problem some languages have of making it hard to distinguish from the block's body).
I agree. Putting the args inside the { } is much more readable to me too. Even just putting the parens inside rather than outside seems an improvement. Or how about { int x; int y :: return x+y; }
I'd be fine with that. Actually, I think I like that a little better (for a couple of reasons which I seem to be finding difficult to put into words. It's like, making a clear "split" or division in the block instead of having what looks like this thing that's just kind of floating around, and forever having those two "grouping openers" right next to each other, ie, "{ (" or "{ |" . ) But I'm not sure about replacing the commas with semicolons, unless it meant you could do: { int x, y :: return x+y; } But then, I'm not sure how I feel about that either.
 K&R was like
     int add(x,y)
        int x;
        int y;
     {  return x+y }
Oh that's right, I knew it was something funky like that. (That would be a "bad redundancy". /me nods to Walter's Dobbs article.)
 Oh, and last semicolon of a function should be optional :-)

    { int x; int y :: return x+y }
Now there's a language war waiting to happen ;)
Feb 04 2009
next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Thu, Feb 5, 2009 at 3:20 PM, Nick Sabalausky <a a.a> wrote:
 K&R was like
     int add(x,y)
        int x;
        int y;
     {  return x+y }
Oh that's right, I knew it was something funky like that. (That would be a "bad redundancy". /me nods to Walter's Dobbs article.)
Well the nice thing about it was you could do this: int add(x,y) CrazyLongTypeName x,y; { return x+y } Thereby removing some bad redundancy. --bb
Feb 04 2009
prev sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Thu, Feb 5, 2009 at 1:20 AM, Nick Sabalausky <a a.a> wrote:
 Oh, and last semicolon of a function should be optional :-)

    { int x; int y :: return x+y }
Now there's a language war waiting to happen ;)
Psh! All that has to happen grammatically is that instead of using a raw semicolon to terminate statements, you have a StatementTerminator nonterminal which goes to either semicolon or non-consuming right brace. It's trivial to implement in the compiler too.
Feb 04 2009
prev sibling parent reply BCS <none anon.com> writes:
Hello Nick,

 One #1 I'd be inclined to requier that the function be defined like
 
 void DoIt(int delegate(int) dg...)
 
D laready has this syntax for Typesafe Variadic Functions http://www.digitalmars.com/d/1.0/function.html
I'm not quite convinced either way on this. For what reasons do you think the function header should be required to indicate "this uses block syntax"? What's wrong with just saying "If the last arg a function takes is a delegate, then that delegate can optionally be specified with block syntax."?
I have used bare block statements on occasion and a missing ';' in the wrong place would be nasty to parse. Another option for killing that problem would be to forbid overloading only on a trailing delegate so Foo(int) and Foo(int, int delegate()) would be considered ambiguous (that argues for the ... as then the rule would be to forbid overloading only on block delegates)
Feb 04 2009
parent reply "Nick Sabalausky" <a a.a> writes:
"BCS" <none anon.com> wrote in message 
news:a6268ff24108cb552c70a0af6c news.digitalmars.com...
 Hello Nick,

 One #1 I'd be inclined to requier that the function be defined like

 void DoIt(int delegate(int) dg...)
D laready has this syntax for Typesafe Variadic Functions http://www.digitalmars.com/d/1.0/function.html
I'm not quite convinced either way on this. For what reasons do you think the function header should be required to indicate "this uses block syntax"? What's wrong with just saying "If the last arg a function takes is a delegate, then that delegate can optionally be specified with block syntax."?
I have used bare block statements on occasion and a missing ';' in the wrong place would be nasty to parse. Another option for killing that problem would be to forbid overloading only on a trailing delegate so Foo(int) and Foo(int, int delegate()) would be considered ambiguous (that argues for the ... as then the rule would be to forbid overloading only on block delegates)
I think I see what you mean. Although, that does create an inconsistency that bothers me a bit, because then some functions with trailing delegate params could be called with block syntax and others couldn't. And then the ones that can be called that way have a restriction on overloading and the ones that can't, don't have that restriction. Just seems messy to me. Maybe instead of requiring anything in the declaration, any use of the block statement style could be required to include a paramater list (and disallowing block statement style for varargs): void foo(int a) {/*stuff*/} void foo(int a, void dg(void)) {/*stuff*/} // Ok foo(5, { writefln("hi"); } ); // Ok, calls foo(int) foo(5); { writefln("hi"); } // Illegal (because of [1]) *even* if the // "foo(int)" overload doesn't exist foo(5) { writefln("hi"); } // Ok, calls foo(int, void delegate(void)) foo(5) (void) { writefln("hi"); } // Illegal, because of [2] foo(5); (void) { writefln("hi"); } // [1]: Already Illegal: // (However, this would become ambiguous with [3], // but that could be solved by block-statement-style // being disallowed for varargs) writefln("hi") { writefln("hi"); } // [2]: Already Illegal? (Or is it a "verb-less" // delegate literal expression statement?): (int a) { writefln("hi"); } // [3] writefln("hi", {writefln("hi");} ); This way, it's impossible to take valid code, add or remove a semicolon, and still have valid code (which I think was your main concern?).
Feb 04 2009
parent BCS <ao pathlink.com> writes:
Reply to Nick,

 This way, it's impossible to take valid code, add or remove a
 semicolon, and still have valid code (which I think was your main
 concern?).
 
I think that way can be made even stronger my making the delegate/block need a trailing ';' (it's a function call after all) where a bare block statement does not.
Feb 05 2009
prev sibling parent Yigal Chripun <yigal100 gmail.com> writes:
Bill Baxter wrote:
 On Thu, Feb 5, 2009 at 7:26 AM, BCS<ao pathlink.com>  wrote:
 Reply to Nick,

 "Yigal Chripun"<yigal100 gmail.com>  wrote in message
 news:gmd0u8$fg7$1 digitalmars.com...

 Andrei Alexandrescu wrote:

 BCS wrote:

 Hello bearophile,

 I've taken a look at the syntax for lambda in other C-like
 languages. This is from Functional Java:
 http://functionaljava.org/examples#Array.filter

 In Functional Java you can write this D syntax:
 (int i, int j) { return i % 3 == j; }
 as:
 { int i, int j =>  i % 3 == j }
That syntax, and a few of the below, show the one major gripe I have with ultra-compact lambdas: it's hard to *quickly* spot the args/code transition.
Strings are immune from the problem. :o) Also they make for readily recognizable code because they all use the same argument names. Andrei
Personally I prefer to have syntax for "blocks" like Ruby/smalltalk. given the following example function: int func(int a, delegate int(int) dg) { .. } // call func with [something in this spirit is my favorite]: func(someInt) { | int a, int b | return a+b; }; compare with the current D syntax: func( someInt, (int a, int b) {return a+b;} ); compare with a lamda syntax: func(someInt, { int a, int b => a+b } ); blocks are more useful - they are not limited to just one expression, and I think are a more general construct. lamdas/array comps, are just special cases.
Agreed. This is what I had always been ultimately hoping for. I'd be happy with the string stuff if that "wrong scope" issue gets fixed (that I mentioned in another branch of this thread), but I'd still prefer this (especially if the types for the params could somehow be inferred and omitted like this: ) ).
Why use this: "func(someInt) { |a,b| return a+b; };" when you can reuse syntax and get this for the same amount of typeing "func(someInt) (a,b){ return a+b; };"
I was about to say the same thing, but I think Yigal was just mixing two distinct suggestions together: 1) the trailing delegates proposal (aka ruby block) and 2) A ruby-like syntax for delegate literals : {|a,b| return a+b;} --bb
not exactly. the reason why I changed the syntax like that is because of templates. for example: void func(T, int i)(T a, delegate int(int) dg) {...} with your and BCS' proposal the above would be called like so: func!(SomeType, 15)(someVar)(a,b){ return a+b; }; this is less clear, IMO. besides, I really like Ruby's (and before that Smalltalk's) syntax to handle this. <g> to Nick - you mentioned the scoping problem with strings. Personally I *HATE* this use of strings. it has many issues which I already mentioned in previous posts. to specifically address your point - what your looking for is called "Hygienic Macros" - http://en.wikipedia.org/wiki/Hygienic_macros basically you want to control which arguments to your AST macro are evaluated at which scope. This i'd like to see implemented in D when AST macros are added.
Feb 04 2009
prev sibling parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
BCS wrote:
 
 Why use this:
 
 "func(someInt) { |a,b| return a+b; };"
 
 when you can reuse syntax and get this for the same amount of typeing
 
 "func(someInt) (a,b){ return a+b; };"
 
 
While I know the compiler could (should) know the difference easily enough, my eyes want to parse that as a chained call followed bizarrely by a naked block, rather than a block. That said, I've always found blocks to be one of Ruby's niftiest features (I do a fair bit of Ruby hackage on the side), and would love to see something like it in D2. -- Chris Nicholson-Sauls
Feb 05 2009
prev sibling parent reply BCS <ao pathlink.com> writes:
Reply to Yigal,

 Personally I prefer to have syntax for "blocks" like Ruby/smalltalk.
 given the following example function:
 int func(int a, delegate int(int) dg) { .. }
 // call func with [something in this spirit is my favorite]:
 func(someInt) { | int a, int b | return a+b; };
 
how about require that the block arg in the called function name the args
 int func(int a, delegate int(int val, int thing) dg) { .. }
and then pull in those names implicitly
 func(someInt) { return val+thing; };
This would have implication in overloading and what not but it would be syntactically clean.
Feb 05 2009
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
BCS wrote:
 Reply to Yigal,
 
 Personally I prefer to have syntax for "blocks" like Ruby/smalltalk.
 given the following example function:
 int func(int a, delegate int(int) dg) { .. }
 // call func with [something in this spirit is my favorite]:
 func(someInt) { | int a, int b | return a+b; };
how about require that the block arg in the called function name the args
 int func(int a, delegate int(int val, int thing) dg) { .. }
and then pull in those names implicitly
 func(someInt) { return val+thing; };
This would have implication in overloading and what not but it would be syntactically clean.
Ew, no. Aside from the technical issues, this distances the names from the use thereof (i.e. they'd likely be in separate files)
Feb 05 2009
parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Robert Fraser wrote:
 BCS wrote:
 Reply to Yigal,

 Personally I prefer to have syntax for "blocks" like Ruby/smalltalk.
 given the following example function:
 int func(int a, delegate int(int) dg) { .. }
 // call func with [something in this spirit is my favorite]:
 func(someInt) { | int a, int b | return a+b; };
how about require that the block arg in the called function name the args
 int func(int a, delegate int(int val, int thing) dg) { .. }
and then pull in those names implicitly
 func(someInt) { return val+thing; };
This would have implication in overloading and what not but it would be syntactically clean.
Ew, no. Aside from the technical issues, this distances the names from the use thereof (i.e. they'd likely be in separate files)
While I fundamentally agree, it could also be nice to /allow/ the names in the decleration, as they may be useful for documentation. -- Chris Nicholson-Sauls
Feb 05 2009
prev sibling next sibling parent reply hsyl20 <hsyl20 yahoo.fr> writes:
 In D (with dlibs) it is:
 
 auto a = [97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42];
 auto b = a.filter((int i){return !(i % 2);});
 
 In Python:
 
 a = [97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42]
 b = [x for x in a if not(i % 2)]
In Scala : val a = List(97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42) val b = a filter (_ % 2 == 0) or val b = a filter (e => e % 2 == 0) or val b = a filter (e : Int => e % 2 == 0) or val b = for (e <- a if (e % 2 == 0)) yield e The first notation "_ % 2 == 0" has no boilerplate and Scala is statically typed (unlike Python). Cheers, Sylvain
Feb 04 2009
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
hsyl20:
 In Scala :
 The first notation "_ % 2 == 0" has no boilerplate and Scala is statically
typed (unlike Python).
There's a subtle line between "no boilerplate" and "magic (variables)", and the Python syntax is less magic there. So thanks but no thanks. I like the type system of Scala, but not every other thing it currently contains. And if you want static typing take a look at ShedSkin, or RPython. Bye, bearophile
Feb 04 2009
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"hsyl20" <hsyl20 yahoo.fr> wrote in message 
news:gmd862$1741$1 digitalmars.com...
 In D (with dlibs) it is:

 auto a = [97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42];
 auto b = a.filter((int i){return !(i % 2);});

 In Python:

 a = [97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42]
 b = [x for x in a if not(i % 2)]
In Scala : val a = List(97, 44, 67, 3, 22, 90, 1, 77, 98, 1078, 6, 64, 6, 79, 42) val b = a filter (_ % 2 == 0) or val b = a filter (e => e % 2 == 0) or val b = a filter (e : Int => e % 2 == 0) or val b = for (e <- a if (e % 2 == 0)) yield e The first notation "_ % 2 == 0" has no boilerplate and Scala is statically typed (unlike Python).
I like that very much, especially since you can use either the implicit _ or a manually named var. Although I would prefer something like "a", "b", etc, (or maybe "_1", "_2",. etc) instead of "_", because "_" doesn't seem to lend itself well to multi-arg lambdas, for instance, with reduce(). I don't like *needing* to name a var when it's something trivial like in the above examples.
Feb 04 2009
parent reply hsyl20 <hsyl20 yahoo.fr> writes:
Nick Sabalausky Wrote:
 The first notation "_ % 2 == 0" has no boilerplate and Scala is statically 
 typed (unlike Python).
I like that very much, especially since you can use either the implicit _ or a manually named var. Although I would prefer something like "a", "b", etc, (or maybe "_1", "_2",. etc) instead of "_", because "_" doesn't seem to lend itself well to multi-arg lambdas, for instance, with reduce(). I don't like *needing* to name a var when it's something trivial like in the above examples.
You can use several "_", for instance: scala> val a = List(10,5,2,48,75,84,96,85,3,21,52) a: List[Int] = List(10, 5, 2, 48, 75, 84, 96, 85, 3, 21, 52) scala> val b = a reduceLeft (_ + _) b: Int = 481 The only problem is if you want to change arg order. In this case you have to use named parameters. scala> val b = a reduceLeft (_ - _) b: Int = -461 scala> val b = a reduceLeft ((a,b) => b - a) b: Int = -5 Cheers Sylvain
Feb 04 2009
parent Yigal Chripun <yigal100 gmail.com> writes:
hsyl20 wrote:
 Nick Sabalausky Wrote:
 The first notation "_ % 2 == 0" has no boilerplate and Scala is statically
 typed (unlike Python).
I like that very much, especially since you can use either the implicit _ or a manually named var. Although I would prefer something like "a", "b", etc, (or maybe "_1", "_2",. etc) instead of "_", because "_" doesn't seem to lend itself well to multi-arg lambdas, for instance, with reduce(). I don't like *needing* to name a var when it's something trivial like in the above examples.
You can use several "_", for instance: scala> val a = List(10,5,2,48,75,84,96,85,3,21,52) a: List[Int] = List(10, 5, 2, 48, 75, 84, 96, 85, 3, 21, 52) scala> val b = a reduceLeft (_ + _) b: Int = 481 The only problem is if you want to change arg order. In this case you have to use named parameters. scala> val b = a reduceLeft (_ - _) b: Int = -461 scala> val b = a reduceLeft ((a,b) => b - a) b: Int = -5 Cheers Sylvain
this seems counter-intuitive to me. Nemerle uses this syntax for currying which seems to me a much better meaning to this syntax. for example ( using D like syntax): int func (string a, char b, int c) { ... } auto a = func( "hello", _, 8); the above is syntax sugar for: auto a = int(char b) { return func("hello", b, 8); };
Feb 05 2009
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
bearophile Wrote:

 C#2 has lambdas, and C#3 adds closures and more type inferencing, so C#3+
supports the following syntaxes:
 (int i) => { return i % 3 == 1; } // C#2
 i => i % 3 == 1 // C#3
 i => { return i % 3 == 1; } // C#3, with statements too
 To define a delegate o delegate closure:
 Func<int> foo = i => { return i % 3 == 1; };
 Func<int> foo = i => i % 3 == 1;
 Func<int> bar = () => 2;
 But this isn't allowed:
 Func<void> bar = () => 2;
Yeah, C# lambdas are the killer feature. Slick, readable, C-compatible. Anders knows his job. Let's face it: delegate literals suck a little, mixins as delegates suck a lot, the former is too verbose, the latter just sucks.
Feb 05 2009
next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Thu, 05 Feb 2009 12:32:15 +0300, Kagamin <spam here.lot> wrote:

 bearophile Wrote:

 C#2 has lambdas, and C#3 adds closures and more type inferencing, so  
 C#3+ supports the following syntaxes:
 (int i) => { return i % 3 == 1; } // C#2
 i => i % 3 == 1 // C#3
 i => { return i % 3 == 1; } // C#3, with statements too
 To define a delegate o delegate closure:
 Func<int> foo = i => { return i % 3 == 1; };
 Func<int> foo = i => i % 3 == 1;
 Func<int> bar = () => 2;
 But this isn't allowed:
 Func<void> bar = () => 2;
Yeah, C# lambdas are the killer feature. Slick, readable, C-compatible. Anders knows his job. Let's face it: delegate literals suck a little, mixins as delegates suck a lot, the former is too verbose, the latter just sucks.
I don't like C# lambda syntax (although it is not half as bad as C++ lambda syntax). I believe D delegate syntax is superior due to its natural and unambiguous syntax. But yes, it could be made shorter by improving type deduction: int delegate(int) inc = (i) { i + 1; } Which would be the same as int delegate(int) inc = (int i) { return i + 1; } where i's type is deduced from inc's type and the only expression (i + 1) made a return value: auto x = inc(5); // yields 6 Here is an another example: void foo(void delegate(ref int i) inc); Could be used as follows: foo( (i) { ++i; } ); as opposed to foo( (ref int i) { ++i; } ); I can put this enhancement request into bugzilla if anyone likes it.
Feb 05 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Denis Koroskin wrote:
 On Thu, 05 Feb 2009 12:32:15 +0300, Kagamin <spam here.lot> wrote:
 
 bearophile Wrote:

 C#2 has lambdas, and C#3 adds closures and more type inferencing, so 
 C#3+ supports the following syntaxes:
 (int i) => { return i % 3 == 1; } // C#2
 i => i % 3 == 1 // C#3
 i => { return i % 3 == 1; } // C#3, with statements too
 To define a delegate o delegate closure:
 Func<int> foo = i => { return i % 3 == 1; };
 Func<int> foo = i => i % 3 == 1;
 Func<int> bar = () => 2;
 But this isn't allowed:
 Func<void> bar = () => 2;
Yeah, C# lambdas are the killer feature. Slick, readable, C-compatible. Anders knows his job. Let's face it: delegate literals suck a little, mixins as delegates suck a lot, the former is too verbose, the latter just sucks.
I don't like C# lambda syntax (although it is not half as bad as C++ lambda syntax). I believe D delegate syntax is superior due to its natural and unambiguous syntax. But yes, it could be made shorter by improving type deduction: int delegate(int) inc = (i) { i + 1; } Which would be the same as int delegate(int) inc = (int i) { return i + 1; }
What if you wanted to just execute one expression and return void? This is relevant when e.g. large objects are involved that shouldn't be copied unwittingly.
 where i's type is deduced from inc's type and the only expression (i + 
 1) made a return value:
 
 auto x = inc(5); // yields 6
 
 Here is an another example:
 
 void foo(void delegate(ref int i) inc);
 
 Could be used as follows:
 
 foo( (i) { ++i; } );
 
 as opposed to
 
 foo( (ref int i) { ++i; } );
Aha! So here you are using a void-returning function. Now what if there was another overload of foo in place: void foo(int delegate(ref int i) inc); Which foo is to be called? The one that infers a return type of int or the one that assumes the code just returns void?
 I can put this enhancement request into bugzilla if anyone likes it.
It would be great to add the parameter type deduction stuff; that is already talked about and doesn't seem to have many issues. It does have one, which I'm sure people here will see rather quickly. Andrei
Feb 05 2009
parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Thu, 05 Feb 2009 17:25:38 +0300, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

 Denis Koroskin wrote:
 On Thu, 05 Feb 2009 12:32:15 +0300, Kagamin <spam here.lot> wrote:

 bearophile Wrote:

 C#2 has lambdas, and C#3 adds closures and more type inferencing, so  
 C#3+ supports the following syntaxes:
 (int i) => { return i % 3 == 1; } // C#2
 i => i % 3 == 1 // C#3
 i => { return i % 3 == 1; } // C#3, with statements too
 To define a delegate o delegate closure:
 Func<int> foo = i => { return i % 3 == 1; };
 Func<int> foo = i => i % 3 == 1;
 Func<int> bar = () => 2;
 But this isn't allowed:
 Func<void> bar = () => 2;
Yeah, C# lambdas are the killer feature. Slick, readable, C-compatible. Anders knows his job. Let's face it: delegate literals suck a little, mixins as delegates suck a lot, the former is too verbose, the latter just sucks.
I don't like C# lambda syntax (although it is not half as bad as C++ lambda syntax). I believe D delegate syntax is superior due to its natural and unambiguous syntax. But yes, it could be made shorter by improving type deduction: int delegate(int) inc = (i) { i + 1; } Which would be the same as int delegate(int) inc = (int i) { return i + 1; }
What if you wanted to just execute one expression and return void? This is relevant when e.g. large objects are involved that shouldn't be copied unwittingly.
No problem: void delegate(int) inc = (i) { i + 1; }; which would be transformed into void delegate(int) inc = (int i) { i + 1; }; or void delegate(int) inc = (int i) { return i + 1; }; Both are valid D code according to specs[1]. The second one doesn't compile as of now, but this is a DMD bug, I assume.
 where i's type is deduced from inc's type and the only expression (i +  
 1) made a return value:
  auto x = inc(5); // yields 6
  Here is an another example:
  void foo(void delegate(ref int i) inc);
  Could be used as follows:
  foo( (i) { ++i; } );
  as opposed to
  foo( (ref int i) { ++i; } );
Aha! So here you are using a void-returning function. Now what if there was another overload of foo in place: void foo(int delegate(ref int i) inc); Which foo is to be called? The one that infers a return type of int or the one that assumes the code just returns void?
1) Compiler can flag an ambiguity error at compile time so that user resolve it: foo((i){ ++i; }); // error foo((i){ ++i; return;}); // unambiguous foo((i){ return ++i;}); // unambiguous 2) (The one I prefer) Make (i) { ++i; } return int. The following could be used to force void return type: foo((i){ ++i;; }); // note the double semicolon. It returns void for two reasons: a) second ; evaluates to void b) it is not a single-statement delegate anymore. Implicit return should only be allowed for single statement delegates that are very frequently used (mostly as a predicate) and almost never return void. I doubt it will lead to errors. The very example is rather artificial.
 I can put this enhancement request into bugzilla if anyone likes it.
It would be great to add the parameter type deduction stuff; that is already talked about and doesn't seem to have many issues. It does have one, which I'm sure people here will see rather quickly. Andrei
--- [1]statement.html: ReturnStatement: return; return Expression; Expression is allowed even if the function specifies a void return type. The Expression will be evaluated, but nothing will be returned.
Feb 05 2009
parent reply Kagamin <spam here.lot> writes:
Denis Koroskin Wrote:

 Could be used as follows:
 
 foo( (i) { ++i; } );
Holy shi- Now feel some real power, Luke. :) foo( i => ++i );
     foo((i){ ++i; }); // error
     foo((i){ ++i; return;}); // unambiguous
     foo((i){ return ++i;}); // unambiguous
Feb 09 2009
parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Mon, 09 Feb 2009 13:24:46 +0300, Kagamin <spam here.lot> wrote:

 Denis Koroskin Wrote:

 Could be used as follows:

 foo( (i) { ++i; } );
Holy shi- Now feel some real power, Luke. :) foo( i => ++i );
     foo((i){ ++i; }); // error
     foo((i){ ++i; return;}); // unambiguous
     foo((i){ return ++i;}); // unambiguous
That was just an example. Those short lambdas are often used as predicates. Compare: findAll(array, (i) { i > 3; }); findAll(array, (int i) { return i > 3; });
Feb 09 2009
next sibling parent Kagamin <spam here.lot> writes:
Denis Koroskin Wrote:

 That was just an example. Those short lambdas are often used as predicates.
Compare:
 
 findAll(array, (i) { i > 3; });
 findAll(array, (int i) { return i > 3; });
 
well... you pwnd me :)
Feb 09 2009
prev sibling parent Kagamin <spam here.lot> writes:
Denis Koroskin Wrote:

 Could be used as follows:

 foo( (i) { ++i; } );
Holy shi- Now feel some real power, Luke. :) foo( i => ++i );
     foo((i){ ++i; }); // error
     foo((i){ ++i; return;}); // unambiguous
     foo((i){ return ++i;}); // unambiguous
That was just an example. Those short lambdas are often used as predicates. Compare: findAll(array, (i) { i > 3; }); findAll(array, (int i) { return i > 3; });
array.filter((x){x>3}) array.filter(x => x>3) array.map(dep => dep.director) I've run into one article. It points out that C# operator => can be viewed as convertion, so operations working with such convertions look rather natural and expressive.
Feb 19 2009
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Kagamin wrote:
 bearophile Wrote:
 
 C#2 has lambdas, and C#3 adds closures and more type inferencing, so C#3+
supports the following syntaxes:
 (int i) => { return i % 3 == 1; } // C#2
 i => i % 3 == 1 // C#3
 i => { return i % 3 == 1; } // C#3, with statements too
 To define a delegate o delegate closure:
 Func<int> foo = i => { return i % 3 == 1; };
 Func<int> foo = i => i % 3 == 1;
 Func<int> bar = () => 2;
 But this isn't allowed:
 Func<void> bar = () => 2;
Yeah, C# lambdas are the killer feature. Slick, readable, C-compatible. Anders knows his job.
Without knowing the person, I disagree you could infer that from C#. What I see above is a smörgåsbord of syntaxes that shoot all over the proverbial barn door in the hope that one of them would strike someone's fancy. That strikes me as a rather lousily done job. Also, it is my perception (and not only mine) that C#'s creator completely missed the power of templates and generative programming.
 Let's face it: delegate literals suck a little, mixins as delegates suck a
lot, the former is too verbose, the latter just sucks.
The logic doesn't quite ring, but passons :o). For what it's worth Walter has got positive feedback left and right from his talk discussing the matter. A simplification in defining function literals is being discussed (omitting the type from the parameters) that would simplify template definitions considerably. Beyond that, I don't feel that changes like moving the parameters on one side or the other of "{" would be Earth-shattering. Andrei
Feb 05 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu>Beyond that, I don't feel that changes like moving the
parameters on one side or the other of "{" would be Earth-shattering.<

As you have seen there are several possible syntaxes for anonymous
functions/delegates/closures. And the current syntax already works, so I think
none of such changes can be Earth-shattering.

On the other hand, extensive usage of lambdas with my dlibs has shown me that
having an uncluttered and un-noisy syntax is quite important if you want to use
such functional style a lot, because otherwise noise builds up quickly and in
production code you are forced to split things in several lines, otherwise no
one can read and debug the code you write.

Regarding such noise I can show you an almost extreme example, this is an easy
programming task:
http://projecteuler.net/index.php?section=problems&id=4
Find the largest palindrome made from the product of two 3-digit numbers<
With Python:
 max(i*j for i in xrange(100,1000) for j in xrange(100,1000) if str(i*j) ==
str(i*j)[::-1])
906609 D1 with my dlibs: import d.all; void main() { putr( max(select(i*j, i, xrange(100,1000), j, xrange(100,1000), str(i*j) == str(i*j).reverse)) ); } Notice in this case Python is clearly better, not just because it's more readable, but also because that select() generates items eagerly, while the Python oneliner contains a lazy generator expression. dlibs contain xmap too, but that code is so much more noisy that I don't want to show it :-) I know this isn't an example of code that's normal in production, but sometimes you need extreme example to show your point :-) Now, back to the topic: putting arguments into a single () or {} instead of a (){ return ;} (or with the => of C#) helps the eye see a single visual object isntead of two, this helps the human parsing of the code, improving visual chunking and reducing noise. Bye, bearophile
Feb 05 2009
parent reply Bartosz Milewski <bartosz relisoft.com> writes:
bearophile Wrote:
 Now, back to the topic: putting arguments into a single () or {} instead of a
(){ return ;} (or with the => of C#) helps the eye see a single visual object
isntead of two, this helps the human parsing of the code, improving visual
chunking and reducing noise.
I also believe that, for readability reasons, lambdas should have some distinct token(s) in the beginning. C++ starts lambdas with brackets, []; C# has the distinct =>. I like the Haskell syntax that uses a backslash, which looks very much like lambda. Here's an example of such syntax: auto r = find!( \(a) { return a.Weight > 100; })(range); It goes without saying that any decent D editor would display the backslash as a Greek lambda.
Feb 09 2009
parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Mon, Feb 9, 2009 at 3:19 AM, Bartosz Milewski <bartosz relisoft.com> wro=
te:
 bearophile Wrote:
 Now, back to the topic: putting arguments into a single () or {} instead=
of a (){ return ;} (or with the =3D> of C#) helps the eye see a single vis= ual object isntead of two, this helps the human parsing of the code, improv= ing visual chunking and reducing noise.
 I also believe that, for readability reasons, lambdas should have some di=
stinct token(s) in the beginning. C++ starts lambdas with brackets, []; C# = has the distinct =3D>. I like the Haskell syntax that uses a backslash, whi= ch looks very much like lambda. Here's an example of such syntax:
 auto r =3D find!( \(a) { return a.Weight > 100; })(range);
Far too noisy. auto r =3D find!(\a -> a.Weight > 100)(range); Of course I _may_ be a bit biased in this regard, considering this is the syntax MiniD uses ;) And of course, for multi-statement lambdas: something(\a, b { stmt1; stmt2; });
Feb 09 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Jarrett Billingsley:
 auto r = find!(\a -> a.Weight > 100)(range);
 [...]
 
 something(\a, b
 {
     stmt1;
     stmt2;
 });
This looks better to me (but I don't know if this is the best syntax, it's just an idea): // syntax for lambda that contains a single expression, implicit return (this is the most common case): auto r = find!(a => a.Weight > 100)(range); // syntax for lambda that contains one or more statements, no return, side effects only: something({ a, b :: stmt1; stmt2; }); // syntax for lambda that contains one or more statements, with side effects and return: something({ a, b :: stmt1; return foo(); }); Bye, bearophile
Feb 09 2009
parent reply grauzone <none example.net> writes:
 // syntax for lambda that contains a single expression, implicit return (this
is the most common case):
 auto r = find!(a => a.Weight > 100)(range);
I really like this one, but I'd prefer something like
 auto r = find(range, {a -> a.Weight > 100});
Note the -> instead of the =>, to avoid any ambiguities with the comparison operator.
Feb 09 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
grauzone Wrote:
 I really like this one, but I'd prefer something like
  > auto r = find(range, {a -> a.Weight > 100});
 
 Note the -> instead of the =>, to avoid any ambiguities with the 
 comparison operator.
Let's play more; then what do you think about (all the following are legal): auto r1 = range.find({ x -> x.weight > 100 }); auto r2 = range.find({ x :: return x.weight > 100; }); auto r3 = range.find({ x :: stmt1(x); stmt2; }); auto r4 = range.find({ x, y :: stmt1; return foo(y); }); I like those enough, they seem balanced, uniform, not too much error-prone, they have only one visual chunk, short enough and easy to write :-) Note that this syntax: auto r1 = range.find({ x -> x.weight > 100 }); using my dlibs is equivalent to the following: auto r1 = range.find((ArrayType1!(typeof(range)) x) { return x.weight > 100; }); Bye, bearophile
Feb 09 2009
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
bearophile:
 auto r1 = range.find((ArrayType1!(typeof(range)) x) { return x.weight > 100;
});
Better: auto r1 = range.find((BaseType1!(typeof(range)) x) { return x.weight > 100; }); Of course, you have to specify range twice there, and that's not good. Bye, bearophile
Feb 09 2009
prev sibling parent reply grauzone <none example.net> writes:
bearophile wrote:
 grauzone Wrote:
 I really like this one, but I'd prefer something like
  > auto r = find(range, {a -> a.Weight > 100});

 Note the -> instead of the =>, to avoid any ambiguities with the 
 comparison operator.
Let's play more; then what do you think about (all the following are legal): auto r1 = range.find({ x -> x.weight > 100 }); auto r2 = range.find({ x :: return x.weight > 100; }); auto r3 = range.find({ x :: stmt1(x); stmt2; }); auto r4 = range.find({ x, y :: stmt1; return foo(y); }); I like those enough, they seem balanced, uniform, not too much error-prone, they have only one visual chunk, short enough and easy to write :-)
Agreed. Especially I like that "normal" and "functional" uses have distinct syntax. This is much better than the proposal, to allow omission of the return statement, and to return last value of the last expression statement instead (like in (x){if(x>0) x+=1; x;}).
 Note that this syntax:
 auto r1 = range.find({ x -> x.weight > 100 });
 using my dlibs is equivalent to the following:
 auto r1 = range.find((ArrayType1!(typeof(range)) x) { return x.weight > 100;
});
 
 Bye,
 bearophile
Feb 09 2009
parent "Nick Sabalausky" <a a.a> writes:
"grauzone" <none example.net> wrote in message 
news:gmpgod$fej$1 digitalmars.com...
 bearophile wrote:
 Let's play more; then what do you think about (all the following are 
 legal):

 auto r1 = range.find({ x -> x.weight > 100 });
 auto r2 = range.find({ x :: return x.weight > 100; });
 auto r3 = range.find({ x :: stmt1(x); stmt2; });
 auto r4 = range.find({ x, y :: stmt1; return foo(y); });

 I like those enough, they seem balanced, uniform, not too much 
 error-prone, they have only one visual chunk, short enough and easy to 
 write :-)
Agreed. Especially I like that "normal" and "functional" uses have distinct syntax. This is much better than the proposal, to allow omission of the return statement, and to return last value of the last expression statement instead (like in (x){if(x>0) x+=1; x;}).
I'd rather have everything use "::" (consistent), and then say that the right-hand side of :: can be either A: one or more statements ("normal") or B: an expression ("functional").
Feb 09 2009
prev sibling next sibling parent reply grauzone <none example.net> writes:
 What I see above is a smörgåsbord of syntaxes that shoot all over the 
 proverbial barn door in the hope that one of them would strike someone's 
 fancy. That strikes me as a rather lousily done job. Also, it is my 
I find this statement rather ironic, because you also seem to be quite happy with your code-as-string-literal approach. Your approach doesn't even enforce any syntax, instead, everyone is free to invent his own.
Feb 05 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
grauzone wrote:
 What I see above is a smörgåsbord of syntaxes that shoot all over the 
 proverbial barn door in the hope that one of them would strike 
 someone's fancy. That strikes me as a rather lousily done job. Also, 
 it is my 
I find this statement rather ironic, because you also seem to be quite happy with your code-as-string-literal approach.
I do understand you dislike strings as lambdas, but please do not use that dislike as a presupposition of a truth. Besides, there is no correlation. D offers two syntaxes, a decent lambda syntax (that is being improved) and a string syntax for short predicates. They have clear and distinct tradeoffs and charters. In contrast, C# seems to have decided to allow pretty much all syntax variations that parse unambiguously. You can only wonder what C#4 has in store.
 Your approach doesn't 
 even enforce any syntax, instead, everyone is free to invent his own.
There's only so many ways to write an expression involving one or two given symbols. Andrei
Feb 05 2009
prev sibling parent BCS <ao pathlink.com> writes:
Reply to Andrei,

 Kagamin wrote:

 Also,
 it is my perception (and not only mine) that C#'s creator completely
 missed the power of templates and generative programming.
I have never met the man, but it is my impression that Anders didn't miss the power, he just doesn't care for the paradigm. I would speculate that because there is nothing that it adds that can't be done at runtime (ignoring things like perf), he left it out. C# seems to take the "do stuff as late as you can" approach across the board.
Feb 05 2009
prev sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
Kagamin wrote:
 Yeah, C# lambdas are the killer feature. Slick, readable, C-compatible. Anders
knows his job. Let's face it: delegate literals suck a little, mixins as
delegates suck a lot, the former is too verbose, the latter just sucks.
C# delegates in C# 2.0 are annoying. I try not to use them. The reason: D: void foo(void delegate(int) dg); C#: delegate void SomeName(int i); void foo(SomeName dg); Does C# 3 fix this? I've seen the new syntax for defining delegates, but not for using them.
Feb 05 2009
next sibling parent "Nick Sabalausky" <a a.a> writes:
"Christopher Wright" <dhasenan gmail.com> wrote in message 
news:gmfsqa$311e$1 digitalmars.com...
 Kagamin wrote:
 Yeah, C# lambdas are the killer feature. Slick, readable, C-compatible. 
 Anders knows his job. Let's face it: delegate literals suck a little, 
 mixins as delegates suck a lot, the former is too verbose, the latter 
 just sucks.
C# delegates in C# 2.0 are annoying. I try not to use them. The reason: D: void foo(void delegate(int) dg); C#: delegate void SomeName(int i); void foo(SomeName dg); Does C# 3 fix this? I've seen the new syntax for defining delegates, but not for using them.
C# provided my first introduction to delegates (not counting function-pointers in C), and that oddity actually made it harder for me to really wrap my head around them. Once I did though, I came around to D and thought "Wow! That's so simple!", and it actually helped me understand C#'s delegates better. My only issue with D's delegate-declaration syntax is the semi-messy ordering of "return type, delegate keyword, paramaters, name". Something closer to following would seem much more intuitive to me: void foo(delegate void(int) dg); //or void foo(void dg(int)); //or void foo(delegate(void <- int) dg); //etc... Although, I realize the current way is done to be consistent with function definitions. But, as I mentioned in another branch of the thread, I wouldn't mind function definitions like this: func foo(int <- int x) {return x+1;} //or func foo {(int <- int x) return x+1;} //or func foo {int <- int x :: return x+1;}
Feb 05 2009
prev sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Christopher Wright wrote:
 C#:
 delegate void SomeName(int i);
 void foo(SomeName dg);
Ugh, don't remind me!
Feb 05 2009
prev sibling next sibling parent hsyl20 <hsyl20 yahoo.fr> writes:
 You can use several "_", for instance:
 scala>  val a = List(10,5,2,48,75,84,96,85,3,21,52)
 a: List[Int] = List(10, 5, 2, 48, 75, 84, 96, 85, 3, 21, 52)

 scala>  val b = a reduceLeft (_ + _)
 b: Int = 481

 The only problem is if you want to change arg order. In this case you have to
use named parameters.
 scala>  val b = a reduceLeft (_ - _)
 b: Int = -461

 scala>  val b = a reduceLeft ((a,b) =>  b - a)
 b: Int = -5

 Cheers
 Sylvain
this seems counter-intuitive to me. Nemerle uses this syntax for currying which seems to me a much better meaning to this syntax. for example ( using D like syntax): int func (string a, char b, int c) { ... } auto a = func( "hello", _, 8); the above is syntax sugar for: auto a = int(char b) { return func("hello", b, 8); };
"_" is used for currying in Scala too. scala> def func (a:Int)(b:String) = {} func: (Int)(String)Unit Unit is the same thing as void in Scala. scala> func (5) _ res7: (String) => Unit = <function> scala> func (_:Int) ("blah") res15: (Int) => Unit = <function> scala> func (_) ("blah") <console>:6: error: missing parameter type for expanded function ((x$1) => func(x$1)("blah")) func (_) ("blah") (I don't know why I have to specify "Int" type. Maybe it has been corrected in the last versions.) Cheers, Sylvain
Feb 06 2009
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
Christopher Wright Wrote:

 D:
 void foo(void delegate(int) dg);
 
 C#:
 delegate void SomeName(int i);
 void foo(SomeName dg);
 
 Does C# 3 fix this? I've seen the new syntax for defining delegates, but 
 not for using them.
C# got anough rope for this :) http://msdn.microsoft.com/en-us/library/bb534303.aspx http://msdn.microsoft.com/en-us/library/bb534803.aspx
Feb 09 2009
parent Christopher Wright <dhasenan gmail.com> writes:
Kagamin wrote:
 Christopher Wright Wrote:
 
 D:
 void foo(void delegate(int) dg);

 C#:
 delegate void SomeName(int i);
 void foo(SomeName dg);

 Does C# 3 fix this? I've seen the new syntax for defining delegates, but 
 not for using them.
C# got anough rope for this :) http://msdn.microsoft.com/en-us/library/bb534303.aspx http://msdn.microsoft.com/en-us/library/bb534803.aspx
Eugh! Just eugh!
Feb 09 2009
prev sibling parent reply Kagamin <spam here.lot> writes:
grauzone Wrote:

 // syntax for lambda that contains a single expression, implicit return (this
is the most common case):
 auto r = find!(a => a.Weight > 100)(range);
I really like this one, but I'd prefer something like > auto r = find(range, {a -> a.Weight > 100}); Note the -> instead of the =>, to avoid any ambiguities with the comparison operator.
auto r = find(range, {a -> a.Weight <- 100}); :)
Feb 10 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Kagamin:
 auto r = find(range, {a -> a.Weight <- 100});
Take a look at how the Fortress language manages spaces inside expressions. It can find a syntax error there, because the spacing is misleading. Bye, bearophile
Feb 10 2009
parent reply Kagamin <spam here.lot> writes:
bearophile Wrote:

 Kagamin:
 auto r = find(range, {a -> a.Weight <- 100});
Take a look at how the Fortress language manages spaces inside expressions. It can find a syntax error there, because the spacing is misleading.
There is no error here, since there's no <- operator, the construct is unabiguous, it just looks weird.
Feb 10 2009
next sibling parent Kagamin <spam here.lot> writes:
Kagamin Wrote:

 auto r = find(range, {a -> a.Weight <- 100});
Take a look at how the Fortress language manages spaces inside expressions. It can find a syntax error there, because the spacing is misleading.
There is no error here, since there's no <- operator, the construct is unabiguous, it just looks weird.
well, every construct can look weird in some environment.
Feb 10 2009
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
Kagamin:
 There is no error here, since there's no <- operator, the construct is
unabiguous, it just looks weird.
In Fortress the syntax of this expression is OK: x + 2 * 3 x + 2*3 This is a syntax error, because the spaces are misleading: x+2 * 3 Bye, bearophile
Feb 10 2009