I've searched a bit about type inference, but I can't seem to apply any of the solutions to my particular problem.
I'm doing a lot of work with building and passing around functions. This seems to me like it should be able to infer the int type. The only thing I can think of is that the lambda return type isn't checked by the type inference algorithm. I have stripped unnecessary logic to show the issue more clearly.
Func<T> Test<T>(Func<Func<T>> func)
{
return func();
}
this compiles:
Func<int> x = Test<int>(() =>
{
int i = 0;
return () => i;
});
but this gives the error "The type arguments for method cannot be inferred from the usage. Try specifying the type arguments explicitly":
Func<int> x = Test(() =>
{
int i = 0;
return () => i;
});
I guess I would just like to know why it works this way and any workarounds.
I would say that the correct answer to the question is given by E.Lippert in SO Why can't an anonymous method be assigned to var?
But let us play with your example a little:
Func<Func<int>> f = () =>
{
int i = 0;
return () => i;
};
Func<int> x = Test(f); //it compiles OK
No problem in type inference with your Func<T> Test<T>(Func<Func<T>> func) here.
The problem is hidden in that you use an anonymous lambda expression, the type of which cannot be inferred. Try this:
var f = () =>
{
int i = 0;
return () => i;
};
It gives Compiler Error CS0815, saying
Cannot assign lambda expression to an implicitly-typed local variable
and the explanation is:
An expression that is used as the initializer for an implicitly typed
variable must have a type. Because anonymous function expressions,
method group expressions, and the null literal expression do not have
a type, they are not appropriate initializers. An implicitly typed
variable cannot be initialized with a null value in its declaration,
although it can later be assigned a value of null.
Now let's try another thing:
var x = Test(() =>
{
Func<int> f = () => 0;
return f;
});
It compiles as well. So the problem with your original example was actually with this line:
return () => i;
We can go further and according to what Eric Lippert says in his answer provide another function to wrap this:
static Func<T> GetFunc<T>(Func<T> f) { return f; }
Now we can rewrite your code like:
var x = Test(() =>
{
int i = 0;
return GetFunc(() => i);
});
And it works as well.
However, as far as I understand, this all is an overhead and you should just provide an explicit type. While these workarounds are suitable, when you need to have a lambda, returning an object of anonymous type.
Related
I am learning lazy computation, given by the code below
public static Func<R> Map<T, R>(this Func<T> f, Func<T, R> g)
{
return () => g(f());
}
because f could be a computing expensive function to generate T, that's why it is wrapped as Func<T>, but Map returns () => g(f()), where f() is more like a closure which has to be ready first, so it looks to me that f() will still be evaluated in () => g(f()), I know my understanding is wrong, but I couldn't figure what's wrong, so how does compiler kicks in and makes the code still lazy computation (i.e f() will not be called in () => g(f())?
() => g(f()) denotes an anonymous function, nothing more.
Nothing within that function is evaluated at the point of declaration.
f() is only invoked when that anonymous function is invoked, and is invoked every time the anonymous function is invoked.
() => g(f()) is an lambda expression which creates an anonymous function (which is actually a syntactic sugar translated by compiler - see #sharplab).
so it looks to me that f() will still be evaluated in () => g(f())
Yes, when the anonymous function represented by () => g(f()) will be called/evaluated, i.e. (pseudocde):
Func<_> x = () => g(f()); // nothing is evaluated here
x(); // f and g are evaluted here
So laziness is achieved by the fact that computation will be performed not when Map is called but when it's result is invoked, which is easy to check with side-effect. The following:
Func<int> returnsInt = () => 1;
Func<string> mapped = returnsInt.Map(i =>
{
Console.WriteLine("Inside mapping func");
return $"Int is: {i}";
});
// nothing printed yet
Console.WriteLine("Before the eval");
Console.WriteLine(mapped());
Gives next output:
Before the eval
Inside mapping func
Int is: 1
I'm trying to figure out C#'s syntax for anonymous functions, and something isn't making sense to me. Why is this valid
Func<string, string> f = x => { return "Hello, world!"; };
but this isn't?
Func<string> g = { return "Hello, world!"; };
The second still requires the lambda syntax:
Func<string> g = () => { return "Hello, world!"; };
In the first, you're effectively writing:
Func<string, string> f = (x) => { return "Hello, world!"; };
But C# will let you leave off the () when defining a lambda if there is only a single argument, letting you write x => instead. When there are no arguments, you must include the ().
This is specified in section 7.15 of the C# language specification:
In an anonymous function with a single, implicitly typed parameter, the parentheses may be omitted from the parameter list. In other words, an anonymous function of the form
( param ) => expr
can be abbreviated to
param => expr
You need to know the function definition:
Encapsulates a method that has one parameter and returns a value of
the type specified by the TResult parameter.
References:
Microsoft
Why does the following fail to infer R:
static R Foo<R>(Func<Action<R>, R> call) { ... }
While pretty much the 'same', works:
static R Foo<R>(Func<Action, R> call) { ... }
Usage:
var i = Foo(ec => -1);
Ways the first sample 'must' be called to compile:
var i = Foo<int>(ec => -1);
-- or --
var i = Foo((Action<int> ec) => -1);
Thoughts: As can be seen in the second snippet, R is already determined by the return type of the 'lambda'. Why can't the same apply to the first? Even with usage of ec (which should be another compiler hint), it fails to infer.
I think that the problem is not that the compiler if failing to infer R for the function CallWithEscapeContinuation, it is that it is failing to infer a type for the lambda:
ec =>
{
Enumerable.Range(0, 100).Select(x =>
{
// Called here, the compiler has no idea what signature to expect for `ec`
// Could be Action<Int>, could be Action<Decimal> (for example).
if (x == 40) ec(x);
return x;
}).ToList();
return -1;
}
Whereas when you provide the int hint, it can infer what type the lambda is from that and the signature of CallWithEscapeContinuation.
When you just have Action (as opposed to Action<R>) the above is irrelevant because there are no type parameters affecting the possible signatures of the lambda.
I am aware of the following quote:
The reason is that a lambda expression can either be converted to a delegate type or an expression tree - but it has to know which delegate type. Just knowing the signature isn't enough.
Trouble is I am still stuck on how to resolve my problem.
Can someone tell if the below is at all possible?
bool isStaff = () => { return selectedPerson.PersonType == "Staff"; };
Error:
Cannot convert lambda expression to type 'bool' because it is not a delegate type
I understand the error, but I really want to know how to fix this issue as I have rebounded off this error many times and simply not learnt to how properly use lamda expressions as far as value assignment is concerned.
Thanks for the quick replies fellas:
IMO, it would be awesome of the below was possible:
bool isStaff = (selectedPerson, bool) => { return selectedPerson.PersonType == "Staff"; };
Lol, I don't think that works but is beautiful in line code, to me that looks awesome and what I expect. The answers below seem to suggest otherwise lol!
The problem is that the lambda returns a bool when it is evaluated, but it is not a bool itself.
You can do the following:
Func<bool> func = () => { return selectedPerson.PersonType == "Staff"; };
bool isStaff = func();
This assigns the lambda to a variable, which can then be used to invoke the lambda, and return the desired bool value.
bool isStaff = selectedPerson.PersonType == "Staff";
or
Func<Person, bool> isStaffDelegate = selectedPerson =>
selectedPerson.PersonType == "Staff";
bool isStaff = isStaffDelegate(selectedPerson);
As the compiler says, you need to assign to a delegate or expression tree type. So for example:
Func<bool> isStaff = () => selectedPerson.PersonType == "Staff";
Now you haven't explained what you're really trying to do, or what selectedPerson is. The above will capture the selectedPerson variable - but you may actually want a Func<Person, bool> instead, as per the_ajp's answer.
I've created a lambda expression at runtime, and want to evaluate it - how do I do that? I just want to run the expression by itself, not against any collection or other values.
At this stage, once it's created, I can see that it is of type Expression<Func<bool>>, with a value of {() => "MyValue".StartsWith("MyV")}.
I thought at that point I could just call var result = Expression.Invoke(expr, null); against it, and I'd have my boolean result. But that just returns an InvocationExpression, which in the debugger looks like {Invoke(() => "MyValue".StartsWith("MyV"))}.
I'm pretty sure I'm close, but can't figure out how to get my result!
Thanks.
Try compiling the expression with the Compile method then invoking the delegate that is returned:
using System;
using System.Linq.Expressions;
class Example
{
static void Main()
{
Expression<Func<Boolean>> expression
= () => "MyValue".StartsWith("MyV");
Func<Boolean> func = expression.Compile();
Boolean result = func();
}
}
As Andrew mentioned, you have to compile an Expression before you can execute it. The other option is to not use an Expression at all, which woul dlook like this:
Func<Boolean> MyLambda = () => "MyValue".StartsWith("MyV");
var Result = MyLambda();
In this example, the lambda expression is compiled when you build your project, instead of being transformed into an expression tree. If you are not dynamically manipulating expression trees or using a library that uses expression trees (Linq to Sql, Linq to Entities, etc), then it can make more sense to do it this way.
The way I would do it is lifted right from here: MSDN example
delegate int del(int i);
static void Main(string[] args)
{
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
}
Also if you want to use an Expression<TDelegate> type then this page: Expression(TDelegate) Class (System.Linq.Expression) has the following example:
// Lambda expression as executable code.
Func<int, bool> deleg = i => i < 5;
// Invoke the delegate and display the output.
Console.WriteLine("deleg(4) = {0}", deleg(4));
// Lambda expression as data in the form of an expression tree.
System.Linq.Expressions.Expression<Func<int, bool>> expr = i => i < 5;
// Compile the expression tree into executable code.
Func<int, bool> deleg2 = expr.Compile();
// Invoke the method and print the output.
Console.WriteLine("deleg2(4) = {0}", deleg2(4));
/* This code produces the following output:
deleg(4) = True
deleg2(4) = True
*/