December 07, 2009
Hello bearophile,

> Michal Minich:
> 
>> But introduction "{ epx }" as delegate/function literal for functions
>> with no arguments, which implicitly returns result of the expression,
>> seems to me as a good idea.
>> 
> It's a special case, and special cases help to kill languages. It's
> not important enough.
> But a general shorter syntax for lambdas is possible, like the C# one.
> Evaluations lazy arguments only 0 or 1 times sounds like a nice idea.
> Bye,
> bearophile

Yes, it works well in C#, and it is one of the best extension of this language (only adding generics was better).

Consider how it works in C#, and how it could in D

// 1. lambda with no parameter  int a;
var t = new Thread (  () => a=42  );

// 2. lambda with one parameter
string[] arr;
Array.FindAll (arr, item => item.Contains ("abc"));
         // 3. lambda with more parameters
Foo (  (a, b) => a + b );

// 4. lambda with statement (previous examples were expressions)
Array.FindAll (arr, item =>  { return item.Contains ("abc"); } );
// curly braces, semicolon and return are required when statement is used.

D could use:

1. auto t = new Thread ( { a=42 } );
or auto t = new Thread ( () { a=42 } );

2. array.findAll (arr, (item) { item.contains ("abc") } );
         3. foo ( (a, b) { a + b } );

4. array.findAll (arr, (item) { return item.contains ("abc"); } );

I'm not proposing this syntax (maybe I probably should, but I have feeling I would not be first). It may not even be possible to parse it, but seems to me more similar to how currently functions are written. In this setting {exp} or {stm} is not *special* case.


December 07, 2009
On Mon, 07 Dec 2009 16:17:10 +0300, Michal Minich <michal.minich@gmail.com> wrote:

> Hello bearophile,
>
>> Michal Minich:
>>
>>> But introduction "{ epx }" as delegate/function literal for functions
>>> with no arguments, which implicitly returns result of the expression,
>>> seems to me as a good idea.
>>>
>> It's a special case, and special cases help to kill languages. It's
>> not important enough.
>> But a general shorter syntax for lambdas is possible, like the C# one.
>> Evaluations lazy arguments only 0 or 1 times sounds like a nice idea.
>> Bye,
>> bearophile
>
> Yes, it works well in C#, and it is one of the best extension of this language (only adding generics was better).
>
> Consider how it works in C#, and how it could in D
>
> // 1. lambda with no parameter  int a;
> var t = new Thread (  () => a=42  );
>
> // 2. lambda with one parameter
> string[] arr;
> Array.FindAll (arr, item => item.Contains ("abc"));
>           // 3. lambda with more parameters
> Foo (  (a, b) => a + b );
>
> // 4. lambda with statement (previous examples were expressions)
> Array.FindAll (arr, item =>  { return item.Contains ("abc"); } );
> // curly braces, semicolon and return are required when statement is used.
>
> D could use:
>
> 1. auto t = new Thread ( { a=42 } );
> or auto t = new Thread ( () { a=42 } );
>

It already works, just try it (but don't forget to put a semicolon at the end).

> 2. array.findAll (arr, (item) { item.contains ("abc") } );
> 3. foo ( (a, b) { a + b } );
>
> 4. array.findAll (arr, (item) { return item.contains ("abc"); } );
>
> I'm not proposing this syntax (maybe I probably should, but I have feeling I would not be first). It may not even be possible to parse it, but seems to me more similar to how currently functions are written. In this setting {exp} or {stm} is not *special* case.
>
>

I believe it would work. And yes, it was already proposed by many others.
December 07, 2009
Hello Denis,

>> 1. auto t = new Thread ( { a=42 } );
>> or auto t = new Thread ( () { a=42 } );
> It already works, just try it (but don't forget to put a semicolon at
> the  end).
> 
>> 2. array.findAll (arr, (item) { item.contains ("abc") } ); 3. foo (
>> (a, b) { a + b } );
>> 
>> 4. array.findAll (arr, (item) { return item.contains ("abc"); } );
>> 
>> I'm not proposing this syntax (maybe I probably should, but I have
>> feeling I would not be first). It may not even be possible to parse
>> it,  but seems to me more similar to how currently functions are
>> written. In  this setting {exp} or {stm} is not *special* case.
>> 
> I believe it would work. And yes, it was already proposed by many
> others.
> 

it works with two differences:

1. the semicolon is required, even if the body consist only of one expression. This is a minor detail.
2. more importantly - parameter types must be specified explicitly. I don't understand why type of b cannot be inferred in this example:

void foo (void delegate (int a) dg)
{
   dg(1);
}

void main ()
{
   foo ( (int b)  { writeln (b); } );
}

Does the type inference has problem with template code or some other combination of features...?


December 07, 2009
On Mon, 07 Dec 2009 16:51:29 +0300, Michal Minich <michal.minich@gmail.com> wrote:

> Hello Denis,
>
>>> 1. auto t = new Thread ( { a=42 } );
>>> or auto t = new Thread ( () { a=42 } );
>> It already works, just try it (but don't forget to put a semicolon at
>> the  end).
>>
>>> 2. array.findAll (arr, (item) { item.contains ("abc") } ); 3. foo (
>>> (a, b) { a + b } );
>>>  4. array.findAll (arr, (item) { return item.contains ("abc"); } );
>>>  I'm not proposing this syntax (maybe I probably should, but I have
>>> feeling I would not be first). It may not even be possible to parse
>>> it,  but seems to me more similar to how currently functions are
>>> written. In  this setting {exp} or {stm} is not *special* case.
>>>
>> I believe it would work. And yes, it was already proposed by many
>> others.
>>
>
> it works with two differences:
>
> 1. the semicolon is required, even if the body consist only of one expression. This is a minor detail.
> 2. more importantly - parameter types must be specified explicitly. I don't understand why type of b cannot be inferred in this example:
>
> void foo (void delegate (int a) dg)
> {
>     dg(1);
> }
>
> void main ()
> {
>     foo ( (int b)  { writeln (b); } );
> }
>
> Does the type inference has problem with template code or some other combination of features...?
>
>

It complicates semantic pass quite significantly: you can't semantically analyze delegate until you analyze "foo". It also can't infer arguments types in some cases:

void foo(T)(void delegate(T) dg);
foo( (a) { a.bar(); } );

Although I believe it is implementable and worth the trouble, there is a little gain in this feature and that's probably why it is low in the list. I think that Walter will give a green light if someone implements the feature and provides a complete patch.

Any volunteers?
December 07, 2009
Denis Koroskin wrote:
> Although I believe it is implementable and worth the trouble, there is a little gain in this feature and that's probably why it is low in the list. I think that Walter will give a green light if someone implements the feature and provides a complete patch.
> 
> Any volunteers?

If someone should step forward to implement this: I would really like to be able to omit the semicolon inside one-statement delegates/lambdas. It makes using them feel much more natural (at least to me) – just look at some Ruby code.
December 07, 2009
"klickverbot" <klickverbot@gmail.com> wrote in message news:hfj6eb$kss$1@digitalmars.com...
> Denis Koroskin wrote:
>> Although I believe it is implementable and worth the trouble, there is a
>> little gain in this feature and that's probably why it is low in the
>> list.
>> I think that Walter will give a green light if someone implements the
>> feature and provides a complete patch.
>>
>> Any volunteers?
>
> If someone should step forward to implement this: I would really like to
> be
> able to omit the semicolon inside one-statement delegates/lambdas. It
> makes
> using them feel much more natural (at least to me) - just look at some
> Ruby
> code.

I've had an idea for a more expanded version of what you propose:

Many operators tend to fall into one of two categories: Separators vs Terminators (separators being ones that are put between two operands, and terminators being ones that are put after each operand). Terminators (like semicolon) have the advantage of being more consistent, easier to edit, and easier to programmatically generate. Separators (like addition) have the advantages of being more convenient and less visually-noisy when there are just a few operands and often just making more sense for the given task (imagine "1+2" being written instead as "1+2+").

Traditionally, every such operator is cemented in stone by the language as being either a separator or a terminator. But D has already noticed, at least in a small way, that sometimes it's better to leave the separator vs terminator choice up to the programmer on a case-by-case basis. Specifically, the commas from array literals and [real] enum declarations can be used either way. This, of course, is done by making the final one optional.

Although I'm one of the people who isn't typically too keen on optional semicolons, I've wondered if it may be a good idea to extend this "optional-final-operator" concept to semicolons. The primary practical reason would be increased convenience and readability for short lambdas (or short functions and classes).

And, at least in theory, this could maybe even be extended to all separators and terminators, including things like arithmetic and logic. Though that wouldn't initially seem to make much sense, the trick would be to just apply the operator's identity value (0 for addition, 1 for multiplication, true for logical and, false for logical or).  But of course, the downside in these cases would be a silent error if you forgot to type the last value.


December 07, 2009
Michal Minich wrote:
> Hello Andrei,
> 
>> Should we sack lazy? I'd like it to have a reasonable replacement.
>> Ideas are welcome!
>>
>> Andrei
>>
> 
> there are 3 sides from which to look at lazy function parameter.
> 
> 1. Usage - being able to send expressions to function is very important for writing clear and nice looking code. I think just by requiring enclosure in curly braces "fun({gun();})" would make this feature quite less appealing and used. This syntactic feature is very pleasing - by whichever feature at definition side it is achieved (macro/expression type), it should stay here.

I think the same. But I seem to recall that at least one person on reddit thought it's a major loss of a guarantee.

> 2. Writing - On the function definition side, I don't see much difference in *writing* "lazy int dg" or "int delegate () dg". The functions that take lazy parameter are not written daily - their usage is much more frequent (enforce, logging).

Nononono. There's a huge difference. If you have "lazy int x", then that's perceived as an int with some sort of storage class. Then a putative user would expect

auto y = x;

to define another int. In fact it's unclear whether y should be an int or a delegate. The presence of the delegate type clarifies what's going on. I could come up with several other examples that reveal "lazy int x" to be a complete crock.

> One problem I see currently with "lazy" that by specification it can be evaluated zero or more times. For me, "lazy" means zero or one time (compiler should handle this internally). This is not particularly important, because it is probably not so hard for programmer to write correct function - evaluation as many times as needed (which I think is usually 0 or 1 anyway). Just, the name "lazy" does not seems correct to me.

I agree. That's why I say we yank it and at most allow function and delegate parameters to accept expressions. That approach has its own problems. Consider:

void fun(int delegate() dg) { ... }
int delegate() gun() { ... }

fun(gun());

In this case gun does get evaluated :o).


Andrei
December 07, 2009
Michal Minich, el  7 de diciembre a las 13:17 me escribiste:
> Hello bearophile,
> 
> >Michal Minich:
> >
> >>But introduction "{ epx }" as delegate/function literal for functions with no arguments, which implicitly returns result of the expression, seems to me as a good idea.
> >>
> >It's a special case, and special cases help to kill languages. It's
> >not important enough.
> >But a general shorter syntax for lambdas is possible, like the C# one.
> >Evaluations lazy arguments only 0 or 1 times sounds like a nice idea.
> >Bye,
> >bearophile
> 
> Yes, it works well in C#, and it is one of the best extension of this language (only adding generics was better).
> 
> Consider how it works in C#, and how it could in D
> 
> // 1. lambda with no parameter  int a;
> var t = new Thread (  () => a=42  );
> 
> // 2. lambda with one parameter
> string[] arr;
> Array.FindAll (arr, item => item.Contains ("abc"));
> // 3. lambda with more parameters
> Foo (  (a, b) => a + b );
> 
> // 4. lambda with statement (previous examples were expressions)
> Array.FindAll (arr, item =>  { return item.Contains ("abc"); } );
> // curly braces, semicolon and return are required when statement is used.
> 
> D could use:
> 
> 1. auto t = new Thread ( { a=42 } );

I think this syntax is pretty neat, because it's make the caller
intentions explicit (and it's very compact). For example, if you write:
  foo({bar()});
Is more obvious that bar() might not be even called. Is like explicit
reference passing (which D doesn't have unfortunately).

I don't know if it's doable though, maybe it's ambiguous?

-- 
Leandro Lucarella (AKA luca)                     http://llucax.com.ar/
----------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------
MP: Cómo está, estimado Bellini?   B: Muy bien, Mario, oraculizando.
MP: Qué tengo?                     B: El auto mal estacionado.
MP: No, en mi mano, Bellini...     B: Una murga!
MP: No, escuche bien. Es de lona.  B: Un ring, Mario.
MP: No Bellini. Tiene cordones.    B: La vereda.
MP: No Bellini! Muy fácil, eh! Es  B: Una modelo, Mario!
    imprescindible para jugar al   B: Un negro, Mario.
    basquet.
MP: No, Bellini, no y no!
	-- El Gran Bellini (Mario Podestá con unas zapatillas de basquet)
December 07, 2009
Mon, 07 Dec 2009 13:17:10 +0000, Michal Minich wrote:

> Hello bearophile,
> 
>> Michal Minich:
>> 
>>> But introduction "{ epx }" as delegate/function literal for functions with no arguments, which implicitly returns result of the expression, seems to me as a good idea.
>>> 
>> It's a special case, and special cases help to kill languages. It's not
>> important enough.
>> But a general shorter syntax for lambdas is possible, like the C# one.
>> Evaluations lazy arguments only 0 or 1 times sounds like a nice idea.
>> Bye,
>> bearophile
> 
> Yes, it works well in C#, and it is one of the best extension of this language (only adding generics was better).
> 
> Consider how it works in C#, and how it could in D
> 
> // 1. lambda with no parameter
> int a;
> var t = new Thread (  () => a=42  );
> 
> // 2. lambda with one parameter
> string[] arr;
> Array.FindAll (arr, item => item.Contains ("abc"));
> 
> // 3. lambda with more parameters
> Foo (  (a, b) => a + b );

You surely understand that Walter doesn't have enough time to change this before the Andrei's book is out. So D2 won't be getting this. Besides, he hasn't even said that he likes the syntax. And D can't infer the types that way, you would need

> Foo (  (auto a, auto b) => a + b );

or

> Foo (  [T,S](T a, S b) => a + b );

> 
> // 4. lambda with statement (previous examples were expressions)
> Array.FindAll (arr, item =>  { return item.Contains ("abc"); } ); //
> curly braces, semicolon and return are required when statement is used.
> 
> D could use:
> 
> 1. auto t = new Thread ( { a=42 } );
> or auto t = new Thread ( () { a=42 } );
> 
> 2. array.findAll (arr, (item) { item.contains ("abc") } );

Andrei invented the string template parameter hack to avoid this. This would work too slowly since the dmd backend from the 1960s cannot inline anonymous functions. It can only inline named functions.

> 
> 3. foo ( (a, b) { a + b } );
> 
> 4. array.findAll (arr, (item) { return item.contains ("abc"); } );
> 
> I'm not proposing this syntax (maybe I probably should, but I have feeling I would not be first). It may not even be possible to parse it, but seems to me more similar to how currently functions are written. In this setting {exp} or {stm} is not *special* case.

December 07, 2009
Michal Minich, el  7 de diciembre a las 13:51 me escribiste:
> Hello Denis,
> 
> >>1. auto t = new Thread ( { a=42 } );
> >>or auto t = new Thread ( () { a=42 } );
> >It already works, just try it (but don't forget to put a semicolon at
> >the  end).
> >
> >>2. array.findAll (arr, (item) { item.contains ("abc") } ); 3. foo (
> >>(a, b) { a + b } );
> >>
> >>4. array.findAll (arr, (item) { return item.contains ("abc"); } );
> >>
> >>I'm not proposing this syntax (maybe I probably should, but I have feeling I would not be first). It may not even be possible to parse it,  but seems to me more similar to how currently functions are written. In  this setting {exp} or {stm} is not *special* case.
> >>
> >I believe it would work. And yes, it was already proposed by many others.
> >
> 
> it works with two differences:
> 
> 1. the semicolon is required, even if the body consist only of one
> expression. This is a minor detail.
> 2. more importantly - parameter types must be specified explicitly.
> I don't understand why type of b cannot be inferred in this example:
> 
> void foo (void delegate (int a) dg)
> {
>    dg(1);
> }
> 
> void main ()
> {
>    foo ( (int b)  { writeln (b); } );
> }

It doesn't do implicit returning either:

$ cat -n x.d
     1
     2	import std.stdio;
     3
     4	void foo (int delegate() dg)
     5	{
     6		writeln(dg());
     7	}
     8
     9	void main()
    10	{
    11		int a = 5;
    12		foo({a;});
    13	}
    14
$ dmd x.d
x.d(12): Error: var has no effect in expression (a)
x.d(12): Error: function x.foo (int delegate() dg) is not callable using argument types (void delegate())
x.d(12): Error: cannot implicitly convert expression (__dgliteral1) of type void delegate() to int delegate()

To make it work you have to do it like this:
    12		foo({return a;});

Which is considerably uglier than
    12		foo({a});

At least when talking about replacing "lazy" :)

Nobody wants to write:
enforce({ return a == 5; });
instead of:
enforce(a == 5);

But:
enforce({a == 5});

Could be acceptable.


-- 
Leandro Lucarella (AKA luca)                     http://llucax.com.ar/
----------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------
Ambition makes you look pretty ugly