Thread overview | ||||||||
---|---|---|---|---|---|---|---|---|
|
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 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michael | 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 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Maxim Fomin | 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 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | 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 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michael | 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 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | 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) |
Copyright © 1999-2021 by the D Language Foundation