Inline variable declaration outside of scope - c#

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.

Related

Why ternary operator doesn't replace if-else

I've met a little problem and a knowledge gap
I found using If-Else style is too boilerplate sometimes and wanted to replace it with elvis-operator, for example:
Dictionary<string, List<List<int>> VarsWithInfo;
want to replace:
if (VarsWithInfo.ContainsKey(ruleVar))
{
VarsWithInfo[ruleVar] = new List<List<int>> { NestingBlocks };
}
else
{
VarsWithInfo[ruleVar].Add(NestingBlocks);
}
with that:
VarsWithInfo.ContainsKey(ruleVar) ?
VarsWithInfo[ruleVar] = new List<List<int>> { NestingBlocks } :
VarsWithInfo[ruleVar].Add(NestingBlocks);
I know that line with ternar operator is too long in this case, but I want to know the primary reason.
Thank you.
The conditional operator ?:, commonly known as the ternary conditional operator, evaluates a Boolean expression, and returns the result of evaluating one of two expressions, depending on whether the Boolean expression evaluates to true or false
From MSDN
The ternary operator always returns a value. In the expression x = a ? b : c, if a is true then it will assign the value of b to x, otherwise it will assign the value of c to x.
Therefore both b and c need to be expressions which result in a value, and both of those values need to be of the same type.
Neither VarsWithInfo[ruleVar] = new List<List<int>> { NestingBlocks } nor VarsWithInfo[ruleVar].Add(NestingBlocks) are expressions, and they do not return a value. Therefore they cannot be used in a ternary.
I'm assuming your code was supposed to be:
if (!VarsWithInfo.ContainsKey(ruleVar))
{
VarsWithInfo[ruleVar] = new List<List<int>> { NestingBlocks };
}
else
{
VarsWithInfo[ruleVar].Add(NestingBlocks);
}
A common way of writing this is:
if (!VarsWithInfo.TryGetValue(ruleVar, out var list))
{
list = new List<List<int>>();
VarsWithInfo[ruleVar] = list;
}
list.Add(NestingBlocks);
This avoids the duplicate dictionary lookup (i.e. calling VarsWithInfo.ContainsKey(ruleVar) and then reading from VarsWithInfo[ruleVar]).

Modifying a struct in IEnumerable foreach vs List<T>.ForEach

This question is specifically about structs.
Say I define:
struct Complex
{
public double real, imaginary;
}
If I try:
var numbers = new[]
{
new Complex() { real = 1, imaginary = 1 },
new Complex() { real = -1, imaginary = -1 }
};
foreach ( var z in numbers )
{
z.real += 1;
}
I get compilation error: Error: cannot modify members of 'complex' because it is a 'foreach iteration variable'
However,
var numbers = new List<Complex>();
numbers.Add( new Complex() { real = 1, imaginary = 1 } );
numbers.Add( new Complex() { real = -1, imaginary = -1 } );
numbers.ForEach( z => z.real += 1 );
compiles with no error. Keeping the 'foreach' compilation error in mind, is there any reason for not giving a compile-time error here?
TL;DR:
C# tries to protect you from yourself
If you try hard enough, you'll be able to do bad things - the language doesn't protect you from every stupid thing you might do
Mutable structs are bad
Is there any reason for not giving a compile-time error here then?
Yes. You're just modifying a parameter, which is absolutely fine. Parameters aren't deemed read-only, whereas the iteration variable in a foreach loop is deemed read-only. From section 8.8.4 of the C# 5 specification:
During execution of a foreach statement, the iteration variable represents the collection element for which an iteration is currently being performed. A compile-time error occurs if the embedded statement attempts to modify the iteration variable (via assignment or the ++ and -- operators) or pass the iteration variable as a ref or out parameter.
None of this means that using a mutable variable is a good idea - and it also doesn't mean that your ForEach loop will do what you want it to. (The argument was passed to the delegate by value after all.)
If you really want to do something similar (equally ineffective, but hey...) in the foreach version, just write a method in the struct which mutates the fields, then call it from the loop. That's perfectly valid...
// Bad code! Valid, but horrible
foreach (var z in numbers)
{
z.SetReal(z.real + 1);
}
It still won't modify the values in the list... but it won't fail at compile-time.

Why Lambda variable scope exists outside LINQ Query?

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.

Can I capture a local variable into a LINQ Expression as a constant rather than a closure reference?

I'd like to say
int x = magic(), y = moremagic();
return i => i + (x/y);
and have the x be captured as a constant instead of a variable reference. The idea is that x will never change and so when the expression is later compiled, the compiler to can do constant folding and produce more efficient code -- i.e. calculating x/y once instead of on every call, via pointer dereferences into a closure record.
There is no way to mark x as readonly within a method, and the compiler is not clever enough to detect that it doesn't change after the creation of the expression.
I'd hate to have to build the expression by hand. Any brilliant ideas?
UPDATE: I ended up using the marvelous LinqKit to build a partial evaluator that will do the substitutions I want. The transform is only safe if you know that relevant references will not change, but it worked for my purposes. It is possible to restrict the partial evaluation only to direct members of your closure, which you control, by adding an extra check or two in there, which is fairly obvious on inspection of the sample code provided in the LinqKit.
/// <summary>Walks your expression and eagerly evaluates property/field members and substitutes them with constants.
/// You must be sure this is semantically correct, by ensuring those fields (e.g. references to captured variables in your closure)
/// will never change, but it allows the expression to be compiled more efficiently by turning constant numbers into true constants,
/// which the compiler can fold.</summary>
public class PartiallyEvaluateMemberExpressionsVisitor : ExpressionVisitor
{
protected override Expression VisitMemberAccess(MemberExpression m)
{
Expression exp = this.Visit(m.Expression);
if (exp == null || exp is ConstantExpression) // null=static member
{
object #object = exp == null ? null : ((ConstantExpression)exp).Value;
object value = null; Type type = null;
if (m.Member is FieldInfo)
{
FieldInfo fi = (FieldInfo)m.Member;
value = fi.GetValue(#object);
type = fi.FieldType;
}
else if (m.Member is PropertyInfo)
{
PropertyInfo pi = (PropertyInfo)m.Member;
if (pi.GetIndexParameters().Length != 0)
throw new ArgumentException("cannot eliminate closure references to indexed properties");
value = pi.GetValue(#object, null);
type = pi.PropertyType;
}
return Expression.Constant(value, type);
}
else // otherwise just pass it through
{
return Expression.MakeMemberAccess(exp, m.Member);
}
}
}
No there is no way to do this in C#. The compiler does not support capturing variables by value / const. Nor can you convert a non-const value into a const value at runtime in this manner.
Additionally the C# compiler only does constant folding during the initial compilation for known constant values. If it was possible to freeze a value at runtime into a constant it wouldn't participate in compiler constant folding because it happens at runtime.
The compiler doesn't do this type of "value caching". Constant folding is done at compile time for constants only, not for readonly fields and certainly not for local variables which do not have a known value at compile time.
You have to make this yourself, but it has to stay a closure reference (since the value is in fact not determinable at compile time, which is why it is likely to be put in the closure when the expression is built):
int x = magic(), y = moremagic();
int xy = x/y;
return i => i + xy;
x can't be a constant, because you're doing runtime magic to determine what it is. However, if you know that x and y don't change, try:
int x = magic(), y = moremagic();
int xOverY = x/y;
return i => i + xOverY;
I should also mention that even though the compiled IL code for i => i + (x/y) will show the division, the JIT compiler is almost certainly going to optimize this away.
One technique I used in vb2005 was to use a generic delegate factory to effect by-value closures. I only implemented it for subs rather than functions, but it could be done for functions as well. If extended in that way:
FunctionOf.NewInv()
would be a static function which would accept as parameters a function (described later), a T3, and a T4. The passed-in function should accept parameters of types T2, T3, and T4, and return a T1. The function returned by NewInv would accept one parameter of type T2 and call the passed-in function with that parameter and the ones given to NewInv.
The invocation would look something like:
return FunctionOf.NewInv((i,x,y) => i+x/y, x, y)
If you(like me) are creating some expression builder for SQL queries you may consirer the following: first create a class variable, make it a constant and then access it like this:
var constant= Expression.Constant(values);
var start = Expression.MakeMemberAccess(constant, values.GetMemberInfo(f => f.Start));
var end = Expression.MakeMemberAccess(constant, values.GetMemberInfo(f => f.End));
var more = Expression.GreaterThanOrEqual(memberBody, start);
var less = Expression.LessThanOrEqual(memberBody, end);

Declaring collections in C#

My question is: What is the most efficient and correct, for large set of data ?
_pointBuffer1 = new Point3DCollection {
new Point3D(140.961, 142.064, 109.300), new Point3D(142.728, 255.678, (...)
-- or --
_pointBuffer1.Add(new Point3D(140.961, 142.064, 109.300)); _poitBuffer1.Add(142.728, (...)
Or is it the same ?
Point3D is declared as a Point3DCollection, but my question is for any object collection (could be Int32 for example) ..
I would strongly suggest using the collection initializer for the sake of clarity (although I'd use some newlines as well).
They don't quite end up as the same IL, mind you. The first ends up being equivalent to:
var tmp = new Point3DCollection();
tmp.Add(new Point3D(140.961, 142.064, 109.300));
tmp.Add(new Point3D(142.728, 255.678));
...
_pointBuffer1 = tmp;
In other words, the assignment to the eventual variable is only made after all the Add calls.
This is important if your Point3D constructor somehow references _pointBuffer1!
Both are compiled to the same IL. Collection initializers are just syntactic sugar. They will call the Add method. Example:
var res = new List<int>() { 1, 2, 3 };
is compiled to:
List<int> <>g__initLocal0 = new List<int>();
<>g__initLocal0.Add(1);
<>g__initLocal0.Add(2);
<>g__initLocal0.Add(3);
List<int> res = <>g__initLocal0;
The only difference is an additional local variable being declared.
Collection initialisation is syntactic sugar. By this I mean that it is a convenient shorthand that is understood by the complier. The compiler will produce code that is logically identical to calling the collection's add method for each element.

Categories

Resources