On Scope of Variables in .NET(c#) [duplicate] - c#

This question already has answers here:
Variable scope confusion in C#
(4 answers)
Closed 9 years ago.
Reference Code
public void MyMethod()
{
string x;
List sampleList = populateList();
foreach(MyType myType in sampleList)
{
string x; // why is this not allowed?
doSomethingwithX(x);
}
}
I recently started learning C# and today ran into issue with code similar to the above. VS2010 flagged the commented code with this message a local variable named x cannot be declared in this scope because it would give a different meaning to variable x which is already used in parent or current scope to denote something else....
I dont get it...isnt that the whole essence of block statements and scoping...I know i can just change my variable names and go ahead.but i'd like to know WHY?

I dont get it...isnt that the whole essence of block statements and scoping...
No, not really. The intention of scoping isn't "to allow you to reuse names".
I know i can just change my variable names and go ahead.but i'd like to know WHY?
It reduces the possibilities for confusing code, basically. There are various situations where C# prevents you from writing code which is confusing. Not as many as we might like, of course, but where there's no clear benefit from allowing something, and a clear benefit from disallowing it, it makes sense to disallow it.
Would you ever want to work with code that had the same local variable name in scope twice? Wouldn't you always prefer the original developer to use a different name? I would - so I'm glad the compiler enforces that.
Note that this doesn't prevent the same local variable name being used twice in the same method - they just can't be in the same scope. So this is valid:
public void Foo()
{
{
int x = 10;
...
}
{
int x = 10;
...
}
}
But this isn't:
public void Foo()
{
{
int x = 10;
...
}
int x = 10;
...
}
If the second example is confusing, you need to bear in mind that the scope of a local variable is the block in which it was declared - not from the declaration point onwards.

Previously defined x is still in scope that's why compiler stops you from declaring other one.
You can verify this by limiting the scope of previous variable by wrapping it in curly braces -
public void MyMethod()
{
{
string x;
}
List sampleList = populateList();
foreach(MyType myType in sampleList)
{
string x; // This will be fine.
doSomethingwithX(x);
}
}

The x in the for loop is not visible outwith the loop, but the x you declared at the start of the method is visible within the for loop.
Outwith the loop you have one x but inside it there are two, both of which are being declared

You cannot declare string x; again. .. it will have different meaning. Since string x; is declared inside a method. The scope of x will be available through out the method. . So please declare some other variable inside for each loop. ..
Or you can just x. Instead of declaring again. .

Related

lifetime of local variable inside an Action in c# [duplicate]

What is a closure? Do we have them in .NET?
If they do exist in .NET, could you please provide a code snippet (preferably in C#) explaining it?
I have an article on this very topic. (It has lots of examples.)
In essence, a closure is a block of code which can be executed at a later time, but which maintains the environment in which it was first created - i.e. it can still use the local variables etc of the method which created it, even after that method has finished executing.
The general feature of closures is implemented in C# by anonymous methods and lambda expressions.
Here's an example using an anonymous method:
using System;
class Test
{
static void Main()
{
Action action = CreateAction();
action();
action();
}
static Action CreateAction()
{
int counter = 0;
return delegate
{
// Yes, it could be done in one statement;
// but it is clearer like this.
counter++;
Console.WriteLine("counter={0}", counter);
};
}
}
Output:
counter=1
counter=2
Here we can see that the action returned by CreateAction still has access to the counter variable, and can indeed increment it, even though CreateAction itself has finished.
If you are interested in seeing how C# implements Closure read "I know the answer (its 42) blog"
The compiler generates a class in the background to encapsulate the anoymous method and the variable j
[CompilerGenerated]
private sealed class <>c__DisplayClass2
{
public <>c__DisplayClass2();
public void <fillFunc>b__0()
{
Console.Write("{0} ", this.j);
}
public int j;
}
for the function:
static void fillFunc(int count) {
for (int i = 0; i < count; i++)
{
int j = i;
funcArr[i] = delegate()
{
Console.Write("{0} ", j);
};
}
}
Turning it into:
private static void fillFunc(int count)
{
for (int i = 0; i < count; i++)
{
Program.<>c__DisplayClass1 class1 = new Program.<>c__DisplayClass1();
class1.j = i;
Program.funcArr[i] = new Func(class1.<fillFunc>b__0);
}
}
Closures are functional values that hold onto variable values from their original scope. C# can use them in the form of anonymous delegates.
For a very simple example, take this C# code:
delegate int testDel();
static void Main(string[] args)
{
int foo = 4;
testDel myClosure = delegate()
{
return foo;
};
int bar = myClosure();
}
At the end of it, bar will be set to 4, and the myClosure delegate can be passed around to be used elsewhere in the program.
Closures can be used for a lot of useful things, like delayed execution or to simplify interfaces - LINQ is mainly built using closures. The most immediate way it comes in handy for most developers is adding event handlers to dynamically created controls - you can use closures to add behavior when the control is instantiated, rather than storing data elsewhere.
Func<int, int> GetMultiplier(int a)
{
return delegate(int b) { return a * b; } ;
}
//...
var fn2 = GetMultiplier(2);
var fn3 = GetMultiplier(3);
Console.WriteLine(fn2(2)); //outputs 4
Console.WriteLine(fn2(3)); //outputs 6
Console.WriteLine(fn3(2)); //outputs 6
Console.WriteLine(fn3(3)); //outputs 9
A closure is an anonymous function passed outside of the function in which it is created.
It maintains any variables from the function in which it is created that it uses.
A closure is when a function is defined inside another function (or method) and it uses the variables from the parent method. This use of variables which are located in a method and wrapped in a function defined within it, is called a closure.
Mark Seemann has some interesting examples of closures in his blog post where he does a parallel between oop and functional programming.
And to make it more detailed
var workingDirectory = new DirectoryInfo(Environment.CurrentDirectory);//when this variable
Func<int, string> read = id =>
{
var path = Path.Combine(workingDirectory.FullName, id + ".txt");//is used inside this function
return File.ReadAllText(path);
};//the entire process is called a closure.
Here is a contrived example for C# which I created from similar code in JavaScript:
public delegate T Iterator<T>() where T : class;
public Iterator<T> CreateIterator<T>(IList<T> x) where T : class
{
var i = 0;
return delegate { return (i < x.Count) ? x[i++] : null; };
}
So, here is some code that shows how to use the above code...
var iterator = CreateIterator(new string[3] { "Foo", "Bar", "Baz"});
// So, although CreateIterator() has been called and returned, the variable
// "i" within CreateIterator() will live on because of a closure created
// within that method, so that every time the anonymous delegate returned
// from it is called (by calling iterator()) it's value will increment.
string currentString;
currentString = iterator(); // currentString is now "Foo"
currentString = iterator(); // currentString is now "Bar"
currentString = iterator(); // currentString is now "Baz"
currentString = iterator(); // currentString is now null
Hope that is somewhat helpful.
Closures are chunks of code that reference a variable outside themselves, (from below them on the stack), that might be called or executed later, (like when an event or delegate is defined, and could get called at some indefinite future point in time)... Because the outside variable that the chunk of code references may gone out of scope (and would otherwise have been lost), the fact that it is referenced by the chunk of code (called a closure) tells the runtime to "hold" that variable in scope until it is no longer needed by the closure chunk of code...
Basically closure is a block of code that you can pass as an argument to a function. C# supports closures in form of anonymous delegates.
Here is a simple example:
List.Find method can accept and execute piece of code (closure) to find list's item.
// Passing a block of code as a function argument
List<int> ints = new List<int> {1, 2, 3};
ints.Find(delegate(int value) { return value == 1; });
Using C#3.0 syntax we can write this as:
ints.Find(value => value == 1);
If you write an inline anonymous method (C#2) or (preferably) a Lambda expression (C#3+), an actual method is still being created. If that code is using an outer-scope local variable - you still need to pass that variable to the method somehow.
e.g. take this Linq Where clause (which is a simple extension method which passes a lambda expression):
var i = 0;
var items = new List<string>
{
"Hello","World"
};
var filtered = items.Where(x =>
// this is a predicate, i.e. a Func<T, bool> written as a lambda expression
// which is still a method actually being created for you in compile time
{
i++;
return true;
});
if you want to use i in that lambda expression, you have to pass it to that created method.
So the first question that arises is: should it be passed by value or reference?
Pass by reference is (I guess) more preferable as you get read/write access to that variable (and this is what C# does; I guess the team in Microsoft weighed the pros and cons and went with by-reference; According to Jon Skeet's article, Java went with by-value).
But then another question arises: Where to allocate that i?
Should it actually/naturally be allocated on the stack?
Well, if you allocate it on the stack and pass it by reference, there can be situations where it outlives it's own stack frame. Take this example:
static void Main(string[] args)
{
Outlive();
var list = whereItems.ToList();
Console.ReadLine();
}
static IEnumerable<string> whereItems;
static void Outlive()
{
var i = 0;
var items = new List<string>
{
"Hello","World"
};
whereItems = items.Where(x =>
{
i++;
Console.WriteLine(i);
return true;
});
}
The lambda expression (in the Where clause) again creates a method which refers to an i. If i is allocated on the stack of Outlive, then by the time you enumerate the whereItems, the i used in the generated method will point to the i of Outlive, i.e. to a place in the stack that is no longer accessible.
Ok, so we need it on the heap then.
So what the C# compiler does to support this inline anonymous/lambda, is use what is called "Closures": It creates a class on the Heap called (rather poorly) DisplayClass which has a field containing the i, and the Function that actually uses it.
Something that would be equivalent to this (you can see the IL generated using ILSpy or ILDASM):
class <>c_DisplayClass1
{
public int i;
public bool <GetFunc>b__0()
{
this.i++;
Console.WriteLine(i);
return true;
}
}
It instantiates that class in your local scope, and replaces any code relating to i or the lambda expression with that closure instance. So - anytime you are using the i in your "local scope" code where i was defined, you are actually using that DisplayClass instance field.
So if I would change the "local" i in the main method, it will actually change _DisplayClass.i ;
i.e.
var i = 0;
var items = new List<string>
{
"Hello","World"
};
var filtered = items.Where(x =>
{
i++;
return true;
});
filtered.ToList(); // will enumerate filtered, i = 2
i = 10; // i will be overwriten with 10
filtered.ToList(); // will enumerate filtered again, i = 12
Console.WriteLine(i); // should print out 12
it will print out 12, as "i = 10" goes to that dispalyclass field and changes it just before the 2nd enumeration.
A good source on the topic is this Bart De Smet Pluralsight module (requires registration) (also ignore his erroneous use of the term "Hoisting" - what (I think) he means is that the local variable (i.e. i) is changed to refer to the the new DisplayClass field).
In other news, there seems to be some misconception that "Closures" are related to loops - as I understand "Closures" are NOT a concept related to loops, but rather to anonymous methods / lambda expressions use of local scoped variables - although some trick questions use loops to demonstrate it.
A closure aims to simplify functional thinking, and it allows the runtime to manage
state, releasing extra complexity for the developer. A closure is a first-class function
with free variables that are bound in the lexical environment. Behind these buzzwords
hides a simple concept: closures are a more convenient way to give functions access
to local state and to pass data into background operations. They are special functions
that carry an implicit binding to all the nonlocal variables (also called free variables or
up-values) referenced. Moreover, a closure allows a function to access one or more nonlocal variables even when invoked outside its immediate lexical scope, and the body
of this special function can transport these free variables as a single entity, defined in
its enclosing scope. More importantly, a closure encapsulates behavior and passes it
around like any other object, granting access to the context in which the closure was
created, reading, and updating these values.
Just out of the blue,a simple and more understanding answer from the book C# 7.0 nutshell.
Pre-requisit you should know :A lambda expression can reference the local variables and parameters of the method
in which it’s defined (outer variables).
static void Main()
{
int factor = 2;
//Here factor is the variable that takes part in lambda expression.
Func<int, int> multiplier = n => n * factor;
Console.WriteLine (multiplier (3)); // 6
}
Real part:Outer variables referenced by a lambda expression are called captured variables. A lambda expression that captures variables is called a closure.
Last Point to be noted:Captured variables are evaluated when the delegate is actually invoked, not when the variables were captured:
int factor = 2;
Func<int, int> multiplier = n => n * factor;
factor = 10;
Console.WriteLine (multiplier (3)); // 30
A closure is a function, defined within a function, that can access the local variables of it as well as its parent.
public string GetByName(string name)
{
List<things> theThings = new List<things>();
return theThings.Find<things>(t => t.Name == name)[0];
}
so the function inside the find method.
t => t.Name == name
can access the variables inside its scope, t, and the variable name which is in its parents scope. Even though it is executed by the find method as a delegate, from another scope all together.

How does .NET handle variables inside scope

I'm just couris about whats happning behind the scenes. I have this code and of course it will not compile cause I create the hello variable inside a if statement and later try to declare it agian. Why dosen't .NET allow me to do so? Whats happning behind the scences that could make the hello variable interfeer with the one inside the statement.
It's very stright forward why this could interfeer if the variable was declared before the if statement.
public void Test() {
if (true)
{
var hello = "";
}
var hello = "";
Console.Write(hello);
}
The declaration space of a name extends to fill its entire block, even before the declaration.
See Eric Lippert's blog post.
Just to clarify, there are two rules violated here.
The first is that nested local variable declaration spaces may not contain two declarations of the same name.
The second is that nested local scopes may not contain two usages of the same simple name or declaration to mean two different things.
Both rules are violated. Note that the first rule is essentially a special case of the second rule. The second rule is more general; for example, this is also a violation:
class C
{
int x;
void M()
{
if (whatever)
{
string x = "";
}
x = 10;
}
}
Here the simple name x is used to mean this.x in one local scope and the local variable x in a nested scope. This is confusing; a simple name is required to mean the same thing throughout its entire block. We therefore make it illegal. This would be legal:
class C
{
int x;
void M()
{
if (whatever)
{
string x = "";
}
}
}
Even though the local variable is declared in a scope nested inside the scope of the field, this is allowed because the field's scope is not a local variable declaration space.
This is also legal:
class C
{
int x;
void M()
{
if (whatever)
{
string x = "";
}
else
{
x = 2;
}
}
}
because now the two conflicting usages of x are both used consistently throughout the entirity of their immediately containing scopes. Those scopes now do not overlap, so this is allowed. (It is still a bad idea however.)
These rules are there for your safety but they can be quite confusing. See
http://blogs.msdn.com/b/ericlippert/archive/tags/declaration+spaces/
and
http://blogs.msdn.com/b/ericlippert/archive/tags/scope/
for some articles on these language features.
From http://msdn.microsoft.com/en-us/library/aa691132(v=vs.71).aspx:
The scope of a name is the region of program text within which it is possible to refer to the entity declared by the name without qualification of the name. Scopes can be nested, and an inner scope may redeclare the meaning of a name from an outer scope. (This does not, however, remove the restriction imposed by Section 3.3 that within a nested block it is not possible to declare a local variable with the same name as a local variable in an enclosing block.) The name from the outer scope is then said to be hidden in the region of program text covered by the inner scope, and access to the outer name is only possible by qualifying the name.

Is modifying a value type from within a using statement undefined behavior?

This one's really an offshoot of this question, but I think it deserves its own answer.
According to section 15.13 of the ECMA-334 (on the using statement, below referred to as resource-acquisition):
Local variables declared in a
resource-acquisition are read-only, and shall include an initializer. A
compile-time error occurs if the
embedded statement attempts to modify
these local variables (via assignment
or the ++ and -- operators) or
pass them as ref or out
parameters.
This seems to explain why the code below is illegal.
struct Mutable : IDisposable
{
public int Field;
public void SetField(int value) { Field = value; }
public void Dispose() { }
}
using (var m = new Mutable())
{
// This results in a compiler error.
m.Field = 10;
}
But what about this?
using (var e = new Mutable())
{
// This is doing exactly the same thing, but it compiles and runs just fine.
e.SetField(10);
}
Is the above snippet undefined and/or illegal in C#? If it's legal, what is the relationship between this code and the excerpt from the spec above? If it's illegal, why does it work? Is there some subtle loophole that permits it, or is the fact that it works attributable only to mere luck (so that one shouldn't ever rely on the functionality of such seemingly harmless-looking code)?
I would read the standard in such a way that
using( var m = new Mutable() )
{
m = new Mutable();
}
is forbidden - with reason that seem obious.
Why for the struct Mutable it is not allowed beats me. Because for a class the code is legal and compiles fine...(object type i know..)
Also I do not see a reason why changing the contents of the value type does endanger the RA. Someone care to explain?
Maybe someone doing the syntx checking just misread the standard ;-)
Mario
I suspect the reason it compiles and runs is that SetField(int) is a function call, not an assignment or ref or out parameter call. The compiler has no way of knowing (in general) whether SetField(int) is going to mutate the variable or not.
This appears completely legal according to the spec.
And consider the alternatives. Static analysis to determine whether a given function call is going to mutate a value is clearly cost prohibitive in the C# compiler. The spec is designed to avoid that situation in all cases.
The other alternative would be for C# to not allow any method calls on value type variables declared in a using statement. That might not be a bad idea, since implementing IDisposable on a struct is just asking for trouble anyway. But when the C# language was first developed, I think they had high hopes for using structs in lots of interesting ways (as the GetEnumerator() example that you originally used demonstrates).
To sum it up
struct Mutable : IDisposable
{
public int Field;
public void SetField( int value ) { Field = value; }
public void Dispose() { }
}
class Program
{
protected static readonly Mutable xxx = new Mutable();
static void Main( string[] args )
{
//not allowed by compiler
//xxx.Field = 10;
xxx.SetField( 10 );
//prints out 0 !!!! <--- I do think that this is pretty bad
System.Console.Out.WriteLine( xxx.Field );
using ( var m = new Mutable() )
{
// This results in a compiler error.
//m.Field = 10;
m.SetField( 10 );
//This prints out 10 !!!
System.Console.Out.WriteLine( m.Field );
}
System.Console.In.ReadLine();
}
So in contrast to what I wrote above, I would recommend to NOT use a function to modify a struct within a using block. This seems wo work, but may stop to work in the future.
Mario
This behavior is undefined. In The C# Programming language at the end of the C# 4.0 spec section 7.6.4 (Member Access) Peter Sestoft states:
The two bulleted points stating "if the field is readonly...then
the result is a value" have a slightly surprising effect when the
field has a struct type, and that struct type has a mutable field (not
a recommended combination--see other annotations on this point).
He provides an example. I created my own example which displays more detail below.
Then, he goes on to say:
Somewhat strangely, if instead s were a local variable of struct type
declared in a using statement, which also has the effect of making s
immutable, then s.SetX() updates s.x as expected.
Here we see one of the authors acknowledge that this behavior is inconsistent. Per section 7.6.4, readonly fields are treated as values and do not change (copies change). Because section 8.13 tells us using statements treat resources as read-only:
the resource variable is read-only in the embedded statement,
resources in using statements should behave like readonly fields. Per the rules of 7.6.4 we should be dealing with a value not a variable. But surprisingly, the original value of the resource does change as demonstrated in this example:
//Sections relate to C# 4.0 spec
class Test
{
readonly S readonlyS = new S();
static void Main()
{
Test test = new Test();
test.readonlyS.SetX();//valid we are incrementing the value of a copy of readonlyS. This is per the rules defined in 7.6.4
Console.WriteLine(test.readonlyS.x);//outputs 0 because readonlyS is a value not a variable
//test.readonlyS.x = 0;//invalid
using (S s = new S())
{
s.SetX();//valid, changes the original value.
Console.WriteLine(s.x);//Surprisingly...outputs 2. Although S is supposed to be a readonly field...the behavior diverges.
//s.x = 0;//invalid
}
}
}
struct S : IDisposable
{
public int x;
public void SetX()
{
x = 2;
}
public void Dispose()
{
}
}
The situation is bizarre. Bottom line, avoid creating readonly mutable fields.

Can parameters be constant?

I'm looking for the C# equivalent of Java's final. Does it exist?
Does C# have anything like the following:
public Foo(final int bar);
In the above example, bar is a read only variable and cannot be changed by Foo(). Is there any way to do this in C#?
For instance, maybe I have a long method that will be working with x, y, and z coordinates of some object (ints). I want to be absolutely certain that the function doesn't alter these values in any way, thereby corrupting the data. Thus, I would like to declare them readonly.
public Foo(int x, int y, int z) {
// do stuff
x++; // oops. This corrupts the data. Can this be caught at compile time?
// do more stuff, assuming x is still the original value.
}
Unfortunately you cannot do this in C#.
The const keyword can only be used for local variables and fields.
The readonly keyword can only be used on fields.
NOTE: The Java language also supports having final parameters to a method. This functionality is non-existent in C#.
from http://www.25hoursaday.com/CsharpVsJava.html
EDIT (2019/08/13):
I'm throwing this in for visibility since this is accepted and highest on the list. It's now kind of possible with in parameters. See the answer below this one for details.
This is now possible in C# version 7.2:
You can use the in keyword in the method signature. MSDN documentation.
The in keyword should be added before specifying a method's argument.
Example, a valid method in C# 7.2:
public long Add(in long x, in long y)
{
return x + y;
}
While the following is not allowed:
public long Add(in long x, in long y)
{
x = 10; // It is not allowed to modify an in-argument.
return x + y;
}
Following error will be shown when trying to modify either x or y since they are marked with in:
Cannot assign to variable 'in long' because it is a readonly variable
Marking an argument with in means:
This method does not modify the value of the argument used as this parameter.
The answer: C# doesn't have the const functionality like C++.
I agree with Bennett Dill.
The const keyword is very useful. In the example, you used an int and people don't get your point. But, why if you parameter is an user huge and complex object that can't be changed inside that function? That's the use of const keyword: parameter can't change inside that method because [whatever reason here] that doesn't matters for that method. Const keyword is very powerful and I really miss it in C#.
Here's a short and sweet answer that will probably get a lot of down votes. I haven't read all of the posts and comments, so please forgive me if this has been previously suggested.
Why not take your parameters and pass them into an object that exposes them as immutable and then use that object in your method?
I realize this is probably a very obvious work around that has already been considered and the OP is trying to avoid doing this by asking this question, but I felt it should be here none-the-less...
Good luck :-)
I'll start with the int portion. int is a value type, and in .Net that means you really are dealing with a copy. It's a really weird design constraint to tell a method "You can have a copy of this value. It's your copy, not mine; I'll never see it again. But you can't change the copy." It's implicit in the method call that copying this value is okay, otherwise we couldn't have safely called the method. If the method needs the original, leave it to the implementer to make a copy to save it. Either give the method the value or do not give the method the value. Don't go all wishy-washy in between.
Let's move on to reference types. Now it gets a little confusing. Do you mean a constant reference, where the reference itself cannot be changed, or a completely locked, unchangeable object? If the former, references in .Net by default are passed by value. That is, you get a copy of the reference. So we have essentially the same situation as for value types. If the implementor will need the original reference they can keep it themselves.
That just leaves us with constant (locked/immutable) object. This might seem okay from a runtime perspective, but how is the compiler to enforce it? Since properties and methods can all have side effects, you'd essentially be limited to read-only field access. Such an object isn't likely to be very interesting.
Create an interface for your class that has only readonly property accessors. Then have your parameter be of that interface rather than the class itself. Example:
public interface IExample
{
int ReadonlyValue { get; }
}
public class Example : IExample
{
public int Value { get; set; }
public int ReadonlyValue { get { return this.Value; } }
}
public void Foo(IExample example)
{
// Now only has access to the get accessors for the properties
}
For structs, create a generic const wrapper.
public struct Const<T>
{
public T Value { get; private set; }
public Const(T value)
{
this.Value = value;
}
}
public Foo(Const<float> X, Const<float> Y, Const<float> Z)
{
// Can only read these values
}
Its worth noting though, that its strange that you want to do what you're asking to do regarding structs, as the writer of the method you should expect to know whats going on in that method. It won't affect the values passed in to modify them within the method, so your only concern is making sure you behave yourself in the method you're writing. There comes a point where vigilance and clean code are the key, over enforcing const and other such rules.
I know this might be little late.
But for people that are still searching other ways for this, there might be another way around this limitation of C# standard.
We could write wrapper class ReadOnly<T> where T : struct.
With implicit conversion to base type T.
But only explicit conversion to wrapper<T> class.
Which will enforce compiler errors if developer tries implicit set to value of ReadOnly<T> type.
As I will demonstrate two possible uses below.
USAGE 1 required caller definition to change. This usage will have only use in testing for correctness of your "TestCalled" functions code. While on release level/builds you shouldn't use it. Since in large scale mathematical operations might overkill in conversions, and make your code slow. I wouldn't use it, but for demonstration purpose only I have posted it.
USAGE 2 which I would suggest, has Debug vs Release use demonstrated in TestCalled2 function. Also there would be no conversion in TestCaller function when using this approach, but it requires a little more of coding of TestCaller2 definitions using compiler conditioning. You can notice compiler errors in debug configuration, while on release configuration all code in TestCalled2 function will compile successfully.
using System;
using System.Collections.Generic;
public class ReadOnly<VT>
where VT : struct
{
private VT value;
public ReadOnly(VT value)
{
this.value = value;
}
public static implicit operator VT(ReadOnly<VT> rvalue)
{
return rvalue.value;
}
public static explicit operator ReadOnly<VT>(VT rvalue)
{
return new ReadOnly<VT>(rvalue);
}
}
public static class TestFunctionArguments
{
static void TestCall()
{
long a = 0;
// CALL USAGE 1.
// explicite cast must exist in call to this function
// and clearly states it will be readonly inside TestCalled function.
TestCalled(a); // invalid call, we must explicit cast to ReadOnly<T>
TestCalled((ReadOnly<long>)a); // explicit cast to ReadOnly<T>
// CALL USAGE 2.
// Debug vs Release call has no difference - no compiler errors
TestCalled2(a);
}
// ARG USAGE 1.
static void TestCalled(ReadOnly<long> a)
{
// invalid operations, compiler errors
a = 10L;
a += 2L;
a -= 2L;
a *= 2L;
a /= 2L;
a++;
a--;
// valid operations
long l;
l = a + 2;
l = a - 2;
l = a * 2;
l = a / 2;
l = a ^ 2;
l = a | 2;
l = a & 2;
l = a << 2;
l = a >> 2;
l = ~a;
}
// ARG USAGE 2.
#if DEBUG
static void TestCalled2(long a2_writable)
{
ReadOnly<long> a = new ReadOnly<long>(a2_writable);
#else
static void TestCalled2(long a)
{
#endif
// invalid operations
// compiler will have errors in debug configuration
// compiler will compile in release
a = 10L;
a += 2L;
a -= 2L;
a *= 2L;
a /= 2L;
a++;
a--;
// valid operations
// compiler will compile in both, debug and release configurations
long l;
l = a + 2;
l = a - 2;
l = a * 2;
l = a / 2;
l = a ^ 2;
l = a | 2;
l = a & 2;
l = a << 2;
l = a >> 2;
l = ~a;
}
}
If you often run into trouble like this then you should consider "apps hungarian". The good kind, as opposed to the bad kind. While this doesn't normally tries to express constant-ness of a method parameter (that's just too unusual), there is certainly nothing that stops you from tacking an extra "c" before the identifier name.
To all those aching to slam the downvote button now, please read the opinions of these luminaries on the topic:
Eric Lippert
Larry Osterman
Joel Spolsky
If struct is passed into a method, unless it's passed by ref, it will not be changed by the method it's passed into. So in that sense, yes.
Can you create a parameter whose value can't be assigned within the method or whose properties cannot be set while within the method? No. You cannot prevent the value from being assigned within the method, but you can prevent it's properties from being set by creating an immutable type.
The question isn't whether the parameter or it's properties can be assigned to within the method. The question is what it will be when the method exits.
The only time any outside data is going to be altered is if you pass a class in and change one of it's properties, or if you pass a value by using the ref keyword. The situation you've outlined does neither.
The recommended (well, by me) is to use an interface that provides read only access to the members. Remembering that if the "real" member is a reference type, then only provide access to an interface supporting read operations for that type -- recursing down the entire object hierarchy.

Scope of variables in a delegate

I found the following rather strange. Then again, I have mostly used closures in dynamic languages which shouldn't be suspectable to the same "bug". The following makes the compiler unhappy:
VoidFunction t = delegate { int i = 0; };
int i = 1;
It says:
A local variable named 'i' cannot be
declared in this scope because it
would give a different meaning to 'i',
which is already used in a 'child'
scope to denote something else
So this basically means that variables declared inside a delegate will have the scope of the function declared in. Not exactly what I would have expected. I havn't even tried to call the function. At least Common Lisp has a feature where you say that a variable should have a dynamic name, if you really want it to be local. This is particularly important when creating macros that do not leak, but something like that would be helpful here as well.
So I'm wondering what other people do to work around this issue?
To clarify I'm looking for a solution where the variables I declare in the delegete doesn't interfere with variables declared after the delegate. And I want to still be able to capture variables declared before the delegate.
It has to be that way to allow anonymous methods (and lambdas) to use local variables and parameters scoped in the containing method.
The workarounds are to either use different names for the variable, or create an ordinary method.
The "closure" created by an anonymous function is somewhat different from that created in other dynamic languages (I'll use Javascript as an example).
function thing() {
var o1 = {n:1}
var o2 = {dummy:"Hello"}
return function() { return o1.n++; }
}
var fn = thing();
alert(fn());
alert(fn());
This little chunk of javascript will display 1 then 2. The anonymous function can access the o1 variable because it exists on its scope chain. However the anonymous function has an entirely independant scope in which it could create another o1 variable and thereby hide any other further down the scope chain. Note also that all variables in the entire chain remain, hence o2 would continue to exist holding an object reference for as long as the fn varialbe holds the function reference.
Now compare with C# anonymous functions:-
class C1 { public int n {get; set;} }
class C2 { public string dummy { get; set; } }
Func<int> thing() {
var o1 = new C1() {n=1};
var o2 = new C2() {dummy="Hello"};
return delegate { return o1.n++; };
}
...
Func<int> fn = thing();
Console.WriteLine(fn());
Console.WriteLine(fn());
In this case the anonymous function is not creating a truely independant scope any more than variable declaration in any other in-function { } block of code would be (used in a foreach, if, etc.)
Hence the same rules apply, code outside the block cannot access variables declared inside the block but you cannot reuse an identifier either.
A closure is created when the anonymous function is passed outside of the function that it was created in. The variation from the Javascript example is that only those variables actually used by the anonymous function will remain, hence in this case the object held by o2 will be available for GC as soon as thing completes,
You'll also get CS0136 from code like this:
int i = 0;
if (i == 0) {
int i = 1;
}
The scope of the 2nd declaration of "i" is unambiguous, languages like C++ don't have any beef with it. But the C# language designers decided to forbid it. Given the above snippet, do you think still think that was a bad idea? Throw in a bunch of extra code and you could stare at this code for a while and not see the bug.
The workaround is trivial and painless, just come up with a different variable name.
It's because the delegate can reference variables outside the delegate:
int i = 1;
VoidFunction t = delegate { Console.WriteLine(i); };
If I remember correctly, the compiler creates a class member of the outside variables referenced in the anonymous method, in order to make this work.
Here is a workaround:
class Program
{
void Main()
{
VoidFunction t = RealFunction;
int i = 1;
}
delegate void VoidFunction();
void RealFunction() { int i = 0; }
}
Actually, the error doesn't seem to have anything to do with anonymous delegates or lamda expressions. If you try to compile the following program ...
using System;
class Program
{
static void Main()
{
// Action t = delegate
{
int i = 0;
};
int i = 1;
}
}
... you get exactly the same error, no matter whether you comment in the line or not. The error help shows a very similar case. I think it is reasonable to disallow both cases on the grounds that programmers could confuse the two variables.

Categories