Thread overview
about lambdas
Jan 02, 2013
Michael
Jan 02, 2013
Maxim Fomin
Jan 02, 2013
Timon Gehr
Jan 03, 2013
Michael
Jan 03, 2013
Timon Gehr
Jan 03, 2013
Michael
January 02, 2013
R  With(I, R)(I o, R function (I) fun)
{
	static if(isAssignable!(I, typeof(null)))
		return o is null ? null : fun(o);
	else
		return fun(o);
}

class Person
{
	private
	{
		string  _name;
		Address _address;
	}

	@property
	{
		string name() { return	_name; }
		void   name(string v) { _name = v; }

		Address address() { return _address; }
		void	address(Address v) { _address = v; }
	}
}

in main function
----------------
foreach(p; persons)	
	p.With((Person x) => x.address); // works

but
----------------
foreach(p; persons)	
		p.With(x => x.address); // error

nullcheck.d(89): Error: template maybe.With does not match any function template
 declaration. Candidates are:
maybe.d(20):        maybe.With(I, R)(I o, R function(I) fun)
nullcheck.d(89): Error: template maybe.With(I, R)(I o, R function(I) fun) cannot
 deduce template function from argument types !()(Person,void)


Why?



January 02, 2013
On Wednesday, 2 January 2013 at 21:00:10 UTC, Michael wrote:
> R  With(I, R)(I o, R function (I) fun)
> {
> 	static if(isAssignable!(I, typeof(null)))
> 		return o is null ? null : fun(o);
> 	else
> 		return fun(o);
> }
>
> class Person
> {
> 	private
> 	{
> 		string  _name;
> 		Address _address;
> 	}
>
> 	@property
> 	{
> 		string name() { return	_name; }
> 		void   name(string v) { _name = v; }
>
> 		Address address() { return _address; }
> 		void	address(Address v) { _address = v; }
> 	}
> }
>
> in main function
> ----------------
> foreach(p; persons)	
> 	p.With((Person x) => x.address); // works
>
> but
> ----------------
> foreach(p; persons)	
> 		p.With(x => x.address); // error
>
> nullcheck.d(89): Error: template maybe.With does not match any function template
>  declaration. Candidates are:
> maybe.d(20):        maybe.With(I, R)(I o, R function(I) fun)
> nullcheck.d(89): Error: template maybe.With(I, R)(I o, R function(I) fun) cannot
>  deduce template function from argument types !()(Person,void)
>
>
> Why?

The first one is a lambda function, the second one is a lambda template. Templates have type void.
January 02, 2013
On Wednesday, 2 January 2013 at 21:12:33 UTC, Maxim Fomin wrote:
> On Wednesday, 2 January 2013 at 21:00:10 UTC, Michael wrote:
>> R  With(I, R)(I o, R function (I) fun)
>> {
>> 	static if(isAssignable!(I, typeof(null)))
>> 		return o is null ? null : fun(o);
>> 	else
>> 		return fun(o);
>> }
>>
>> ...
>>
>> in main function
>> ----------------
>> foreach(p; persons)	
>> 	p.With((Person x) => x.address); // works
>>
>> but
>> ----------------
>> foreach(p; persons)	
>> 		p.With(x => x.address); // error
>>
>> nullcheck.d(89): Error: template maybe.With does not match any function template
>> declaration. Candidates are:
>> maybe.d(20):        maybe.With(I, R)(I o, R function(I) fun)
>> nullcheck.d(89): Error: template maybe.With(I, R)(I o, R function(I) fun) cannot
>> deduce template function from argument types !()(Person,void)
>>
>>
>> Why?
>
> The first one is a lambda function, the second one is a lambda template. Templates have type void.

Actually the 'void' is just a diagnostics bug. (lambda templates only exist in template parameter lists.) The reason the matching fails is that IFTI is not smart enough to devise a type for the parameter 'x', and therefore no type for 'R' is obtained, what makes the matching fail. Currently other parameters are not taken into account during IFTI matching. I believe that the reason is that otherwise the compiler needs to be clever about the order in which it analyzes the parameters. I consider this one of the more annoying limitations.

A workaround that should work in this case is to use a template parameter:

auto With(alias fun, I)(I o) // maybe add a template constraint here
{
	static if(isAssignable!(I, typeof(null)))
		return o is null ? null : fun(o);
	else
		return fun(o);
}

---

foreach(p; persons)	
    p.With!(x => x.address);

This creates a template from the lambda, and instantiates it once inside 'With'. This way the return type does not have to be part of the template parameters.
January 03, 2013
Thanks guys)

>
> auto With(alias fun, I)(I o) // maybe add a template constraint here
> {
> 	static if(isAssignable!(I, typeof(null)))
> 		return o is null ? null : fun(o);
> 	else
> 		return fun(o);
> }
>
> foreach(p; persons)	
>     p.With!(x => x.address);
>

Now if I want add a somewhat task into expression "x => x.address", for example "writeln(x.address)", a code should be rewritten like

>
> foreach(p; persons)
>     p.With!(x => {writeln(x.address); return x.address;}());
>

As I understand, right part of expression above - "{ ... }()" is anonymous function (or delegate, or closure) that immediately called in lambda expression. Right? Is right behaviour?
January 03, 2013
On 01/03/2013 10:54 PM, Michael wrote:
> Thanks guys)
>
>>
>> auto With(alias fun, I)(I o) // maybe add a template constraint here
>> {
>>     static if(isAssignable!(I, typeof(null)))
>>         return o is null ? null : fun(o);
>>     else
>>         return fun(o);
>> }
>>
>> foreach(p; persons)
>>     p.With!(x => x.address);
>>
>
> Now if I want add a somewhat task into expression "x => x.address", for
> example "writeln(x.address)", a code should be rewritten like
>
>>
>> foreach(p; persons)
>>     p.With!(x => {writeln(x.address); return x.address;}());
>>
>
> As I understand, right part of expression above - "{ ... }()" is
> anonymous function (or delegate, or closure) that immediately called in
> lambda expression. Right? Is right behaviour?

You understand this correctly, but it is a somewhat roundabout way to achieve what you want to do.

This should work as well:

foreach(p; persons)
    p.With!((x){writeln(x.address); return x.address;});

The reason is that there are two different ways for forming function literals. The lambda literal a=>exp is immediately rewritten to (a){ return exp; }

Historically, the lambda syntax has not been available, turning function literal heavy code into something that looked like
{return{return(){return((){return}())}. The introduction of '=>' was a backwards-compatible addition.

January 03, 2013
I just doing a chained null checks.

And I prefer when code looks like "a => ...".

In any case we have two ways to do same thing: "a => {...}()" and "(a){...}".

Thanks Timon)