View mode: basic / threaded / horizontal-split · Log in · Help
January 02, 2013
about lambdas
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
Re: about lambdas
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
Re: about lambdas
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
Re: about lambdas
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
Re: about lambdas
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
Re: about lambdas
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)
Top | Discussion index | About this forum | D home