www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - about lambdas

reply "Michael" <pr m1xa.com> writes:
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?
Jan 02 2013
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
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.
Jan 02 2013
parent reply "Timon Gehr" <timon.gehr gmx.ch> writes:
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.
Jan 02 2013
parent reply "Michael" <pr m1xa.com> writes:
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?
Jan 03 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
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.
Jan 03 2013
parent "Michael" <pr m1xa.com> writes:
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)
Jan 03 2013