Jump to page: 1 2 3
Thread overview
Re: Lambda syntax, etc
Feb 05, 2009
Kagamin
Feb 05, 2009
Denis Koroskin
Feb 05, 2009
Denis Koroskin
Feb 09, 2009
Kagamin
Feb 09, 2009
Denis Koroskin
Feb 09, 2009
Kagamin
Feb 19, 2009
Kagamin
Feb 05, 2009
bearophile
Feb 09, 2009
Bartosz Milewski
Feb 09, 2009
bearophile
Feb 09, 2009
grauzone
Feb 09, 2009
bearophile
Feb 09, 2009
bearophile
Feb 09, 2009
grauzone
Feb 10, 2009
Nick Sabalausky
Feb 05, 2009
grauzone
Feb 05, 2009
BCS
Feb 05, 2009
Christopher Wright
Feb 06, 2009
Nick Sabalausky
Feb 06, 2009
Robert Fraser
February 05, 2009
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.
February 05, 2009
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.

February 05, 2009
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
February 05, 2009
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
February 05, 2009
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
February 05, 2009
> 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.
February 05, 2009
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.

February 05, 2009
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
February 05, 2009
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.


February 05, 2009
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.
« First   ‹ Prev
1 2 3