I read this question(What is the scope of a lambda variable in C#?)
But it is about Lambda variable scope inside LINQ Query.
Now to my question
Lets say I have a very simple LINQ query.
var Foo = FoobBar.Select(x => x);
var x = somefunction();
Compiler says : A local variable 'x' cannot be declared in this scope because it would give a different meaning to 'x', which is already used in a 'child' scope to denote something else.
Why is that so? Shouldn't Lambda variable cease to exist when LINQ query ends?
EDIT: After reading answers i came to conclusion that its the outside x (returned from function) whose scope extends inside LINQ Query.
It's not about LINQ it's about child scopes.
For example:
foreach (var bar in FooBar.Bars)
{
var x = FooBar.GetFoo();
}
var x = new Foo();
produces exactly the same error message from compiler.
To fix that you just have to place variables in different (non-nesting) scopes. For example:
foreach (var bar in FooBar.Bars)
{
var x = FooBar.GetBar();
}
{
var x = new Foo();
}
Lets look carefully,
var Foo = FoobBar.Select(x => x);
true the scope of x ends in the expression
var x = somefunction()
Now this is interesting, this is scoped for the entire method which holds the lamda expression too, so the compiler cannot distinguish since the scope of the latter overlaps the former. and very informative message too give a different meaning to 'x', which is already used in a 'child' scope (Select as in your case)
Similar scope question
maybe you can include braces around the other so that it's scope is defined
{
var x = somefunction()
}
Think if C# would allow those two variables to exist on same scope level, this will not be possible:
static void test() {
Action<int> x = (z) => {
Console.WriteLine(z);
};
int[] i = { 5,2,0,1,3,1,4 };
var kyrie = i.Select (x => x);
}
How you would say to C# that you wanted to assign the Action delegate named x to kyrie variable; or the vice versa, how you would say to C# you wanted to use the integer projection itself? How C# would resolve that?
And C# scoping resolution is very consistent whether you declare it before the other variable or after the other variables, they are the same. e.g. http://www.anicehumble.com/2012/05/java-said-c-said-scope-consistency.html
To disambiguate those scenario, C# doesn't allow you to compile a program that have variable names that exists on same level
It's all about expressing your intent to the compiler in a non-ambiguous way. And C# did a good job on that regard
It's not clear (to the compiler) which 'x' you mean by the second 'x' (after the =>).
What if you wrote this:
var Foo = FoobBar.Select(y => x);
var x = somefunction();
then that x in the lambda would clash with the 'somefunction' result.
You can't declare two variables with the same name in the same scope.
"Same scope" meaning they either are both inside the current scope
void method()
{
int a;
int a; //wrong!
}
or one is in the current and the other is in a child scope.
void method()
{
int a;
for(;;)
{
int a; //wrong again!
}
}
This is by design and holds for any variable, from ints to lambda references.
Related
Let's say I have two dictionaries with the same keys but with different values.
var metrics1 = new Dictionary<string, double>()
{
{ "Albert", 1.5513 },
{ "Becca", 3.3184 },
{ "Colton", -4.4001 },
{ "Danielle", 6.7 }
};
var metrics2 = new Dictionary<string, double>()
{
{ "Albert", 0.84156 },
{ "Becca", -6.7525 },
{ "Colton", 1.1102 },
{ "Danielle", 0.507944 }
};
If I then choose a dictionary at random to get a value from, using the ternary operator ?:, Visual Studio says that I can inline declare a variable.
var rng = new Random();
var name = "Albert"; // Any name that's present in both dictionaries above
/* Unmodified code */
double metric;
var validName = rng.NextDouble() > 0.5
? metrics1.TryGetValue(name, out metric)
: metrics2.TryGetValue(name, out metric);
/* After suggestion was applied */
// double metric;
var validName = rng.NextDouble() > 0.5
? metrics1.TryGetValue(name, out double metric) // 'metric' is declared here?
: metrics2.TryGetValue(name, out metric);
Why is it that the metric variable in the modified version can be populated by both sides of the ternary ?: operator? Should it not be contained entirely in the scope of the first branch?
Let me answer your comment, // 'metric' is declared here? first. Yes, metric is declared there (well... not technically... see below). To test this try to declare it in the second arm of the ternary statement; if you do this you get,
error CS0841: Cannot use local variable 'metric' before it is declared
on the line containing the first arm. As to,
Why is it that the metric variable in the modified version can be populated by both sides of the ternary ?: operator?
Because the compiler compiles that code to IL that looks something like the IL that would be generated for the previous code, which means in both cases the declaration is above both arms of the ternary assignment.
So for,
Should it not be contained entirely in the scope of the first branch?
the answer is no, because in both cases the declaration is in the scope of the method above the ternary assignment that is also within that scope.
Essentially, the second implementation is just syntactic sugar for the first.
It's possible in c# 7 to declare variables for out variables in argument list:
if (int.TryParse(input, out int result))
WriteLine(result);
Is it possible to declare ("non out") variable in argument list? Like this:
if (!string.IsNullOrEmpty(string result=FuncGetStr()))
WriteLine(result);
You can't do it in the argument list, no.
You could use pattern matching for this, but I wouldn't advise it:
if (FuncGetStr() is string result && !string.IsNullOrEmpty(result))
That keeps the declaration within the source code of the if, but the scope of result is still the enclosing block, so I think it would much simpler just to separate out:
// Mostly equivalent, and easier to read
string result = FuncGetStr();
if (!string.IsNullOrEmpty(result))
{
...
}
There are two differences I can think of:
result isn't definitely assigned after the if statement in the first version
string.IsNullOrEmpty isn't even called in the first version if FuncGetStr() returns null, as the is pattern won't match. You could therefore write it as:
if (FuncGetStr() is string result && result != "")
To be utterly horrible, you could do it, with a helper method to let you use out parameters. Here's a complete example. Please note that I am not suggesting this as something to do.
// EVIL CODE: DO NOT USE
using System;
public class Test
{
static void Main(string[] args)
{
if (!string.IsNullOrEmpty(Call(FuncGetStr, out string result)))
{
Console.WriteLine(result);
}
}
static string FuncGetStr() => "foo";
static T Call<T>(Func<T> func, out T x) => x = func();
}
You can assign variables in statements, but the declaration of the variables should be done outside of them. You can't combine them (outside out and pattern matching, as you already indicated in your question).
bool b;
string a;
if (b = string.IsNullOrEmpty(a = "a")){ }
On the why this behavior is different than with out, etc, Damien_The_Unbeliever's comment might be interesting:
The ability to declare out variables inline arises from the awkwardness that it a) has to be a variable rather than a value and b) there's often nothing too useful to do with the value if you declare it before the function is called. I don't see the same motivations for other such uses.
This question already has an answer here:
Why do I have to copy "this" when using LINQ in a struct (and is it OK if I do)?
(1 answer)
Closed 7 years ago.
Apparently you cannot use the keyword "this" in a method in a struct.
Note that in the below example I do not explicitly type "this" but it is implied when I reference the properties "X" or "Y".
My struct:
public struct Coord
{
public int X;
public int Y;
public Coord(int x, int y)
{
X = x;
Y = y;
}
// some other methods omitted
public List<int> GetPossibles()
{
return LaurenceAI.Values.Where(n => LaurenceAI.Possibilities[X, Y, n]).ToList();
}
}
usage example:
foreach(int numeral in targetCoord.GetPossibles())
{
//do stuff
}
Error:
Error 1 Anonymous methods, lambda expressions, and query expressions inside structs cannot access instance members of 'this'. Consider copying 'this' to a local variable outside the anonymous method, lambda expression or query expression and using the local instead. C:\Projects\Sodoku\SodokuSolver\Sodoku\LaurenceAI.cs 367 74 Sodoku
Questions:
What is the technical reason that a method in a struct cannot use keyword "this"?
Is there an elegant way to fix this so that I don't have to type out the reflection code longhand every time I want a list of possible numerals for a given Coord?
The reason is that structs are passed by value, not by reference. Using this in this context results in typically not what you want - it'll access the this pointer of the copy, not the outer object, and it'll be really confusing when any assignments you make aren't showing in the outer call. It's annoying in this specific circumstance, but in general it's stopping more weird errors.
The error message actually gives you a fairly reasonable solution - copy the values first. Do something like:
public List<int> GetPossibles()
{
var localX = X;
var localY = Y;
return LaurenceAI.Values.Where(n => LaurenceAI.Possibilities[localX, localY, n]).ToList();
}
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Detailed Explanation of Variable Capture in Closures
public class Polynom {
public delegate double Func(double x);
private Func f;
public Polynom(params double[] coef) {
f = (double x) => {
double sum = 0;
for ( int i = 0 ; i < coef.Length ; i++ )
sum += coef[i] * Math.Pow(x,coef.Length-1-i);
return sum;
};
}
public double evaluate(double x) {
return f(x);
}
public static void Main() {
Polynom a=new Polynom(1,1,1);
Polynom b=new Polynom(2 , 2 , 0);
Console.WriteLine(a.evaluate(2));
Console.WriteLine(b.evaluate(2));
Console.ReadKey();
}
}
Notice how the code in f uses coef, while coef is a paramater of the constructor.
if you think about it, that should not work unless it gets a ref copy of coef, because once the constructor done its job, its parameters are suppose to vanish. but somehow, calling f manages to use coef as if it still exists. HOW?
I would love a good deep explantion if someone can explain this...
Another thing that i would like to know is, the code is the same on every Polynom instance, but does every instance get another copy of that same code? if so, is there a way to make my class run with just 1 copy of that code? (like make it static somehow)
Lambdas and other delegates are implemented as closures, special objects created by the compiler that combine a method of your lambda with all the data that the lambda needs to complete its execution. The values of all local variables and parameters that are used inside the lambda are implicitly captured as data members of the closure, so they remain available until the lambda itself is no longer referenced.
You can think of the closure as a special anonymous class created specifically for your lambda. In your case, a closure may look like this:
private Polynom_Closure {
private readonly double[] coef;
public Polynom_Closure(double[] coef) {
this.coef = coef;
}
public double evaluate(double x) {
double sum = 0;
for ( int i = 0 ; i < coef.Length ; i++ )
sum += coef[i] * Math.Pow(x,coef.Length-1-i);
return sum;
}
}
The compiler makes this class invisibly for you, and then inserts its use into your code:
public Polynom(params double[] coef) {
f = new Polynom_Closure(coef).evaluate;
}
The function is a so-called closure, which is well-explained in this wikipedia article
A closure allows a function to access variables outside its immediate lexical scope. An upvalue is a free variable that has been bound (closed over) with a closure. The closure is said to "close over" its upvalues. The referencing environment binds the nonlocal names to the corresponding variables in scope at the time the closure is created, additionally extending their lifetime to at least as long as the lifetime of the closure itself. When the closure is entered at a later time, possibly from a different scope, the function is executed with its non-local variables referring to the ones captured by the closure.
Concerning your second question: Making a closure static would somewhat contradict the purpose of functional principles.
can anyone suggest me the exact use of out keyword as a paramter, and how its connected for returning multiple values from the function, as in this POST, i am confused with out variable with normal variable. can anyone help me for this.
This is frequently confusing, and I think the MSDN documentation actually is a bit "clear only if already known". That is, it is correct, but it really only makes sense if you already understand the concept.
Here's how I think of it.
A regular parameter makes a copy of the value of the argument. When you say:
static int M(int z) { z = z + 1; return z; }
...
int x = 123;
int y = M(x);
That is just like you said:
int x = 123;
int z = x; // make a copy of x
z = z + 1;
int y = z;
A ref or out parameter make an alias for an existing variable. When you say
static void N(ref int q) { q = q + 1; }
...
int x = 123;
N(x);
That is the same as saying:
int x = 123;
// MAGIC: q is now an another name for variable x
q = q + 1;
q and x are two different names that refer to the same variable. Incrementing q also increments x because they are the same. z and x in the previous example are two different names that refer to two different variables. Incrementing z does not change x.
Summing up: "out" and "ref" just mean "do not make a new variable; rather, temporarily make a second name for an existing variable".
Is that now clear?
UPDATE: I did not say what the difference between "out" and "ref" is. The difference is simple. On the "caller" side, a "ref" must be a definitely assigned variable before the method is called. An "out" need not be. On the "callee" side, a "ref" may be read before it is written to, but an "out" must be written to before it is read. Also, an "out" must be written to before control leaves the method normally.
MSDN documentation already does a great job explaining this:
The out keyword causes arguments to be passed by reference. This is
similar to the ref keyword, except that ref requires that the variable
be initialized before being passed. To use an out parameter, both the
method definition and the calling method must explicitly use the out
keyword. For example:
class OutExample
{
static void Method(out int i)
{
i = 44;
}
static void Main()
{
int value;
Method(out value);
// value is now 44
}
}
It's very frequently used in a pattern that "tries" to get a value, something like:
int result;
if(Int32.TryParse("123", out result))
{
Console.WriteLine(result + 1);
}
out keyword should be used when you want to:
a) Allow your function to modify specific variable from calling code stack AND
b) enforce setting this variable value inside your function
MSDN is always a good place to start
In most languages c# included you can pass values in 2 ways, by value, by reference.
by value gives the method a copy of your data, so changing the data wont have any effect on the original data
by reference essentially gives the method the memory address of your data, so if the method modifies the data, it changes the original.
Out is a special type of ref, in that you do not need to initialise the variable before you call the method, it can be called with null being passed in. and it MUST be set by the method.
Another way you can think of it (from the outside code's point of view) is:
val = read only
ref = read/write
out = write only.
http://msdn.microsoft.com/en-us/library/t3c3bfhx(v=vs.80).aspx
out keyword is good if you want to return multiple values of pre-defined types (for example an int, a List<string> and a DateTime), and you don't want to create a new class just for this purpose.
Ok,
let look at the usual pattern for this kind of function - the TrySomething.
Suppose you have a function that might succeed giving you an value or not but you don't won't to use an exception for this because you don't want the overhead or it's a common trait.
Then you normaly return true if the method suceeded and false if not. But where would you put your outputvalue to?
One possible answer is using an out parameter like this:
bool TrySomething(MyInputType input, out MyOutputType output)
{
output = default(MyOutputType);
/* ... Try getting the answer ... */
if (!successful)
return false;
output = successfulOutput;
return true;
}
Remark:
Or you might consider using a Tuple<bool,MyOutputType> and indeed F# interpretes the pattern above as resulting in such a tuple by itself.