Why local variables are not accessible from other functions? - c#

I'm currently learning about computer memory and asking questions to myself to understand it better.
I learned about how a new space is allocated in the stack whenever a function is called.
But why we can't reach local variables even though they are still on the stack? What is it that prevents me from accessing them while they are still on the stack?
Consider the following code (Please look at the comments):
class Program
{
public static void Main()
{
int number = 5;
Method();
} //<------ number variable will be stored in the stack until the program reaches here.
public static void Method()
{
// number=5 variable is still on the stack so why can't I reach it here?
number = 10; // throws an error because it's not defined in this scope but it's still on the stack.
int anotherNumber = 2;
}
}

In C and languages derived from it, functions are separately compiled so they cannot "see" the local variables of each other. This is a design decision.
In Pascal and languages derived from it, this is made possible by allowing nested function declarations. A function declared inside another sees the local variables of the latter as global ones.
But beware that via mutual and recursive calls, the same variable can exist at several places in the stack.

If that code could compile (i.e. if you comment out number = 10;), the variable number would likely not even be on the stack in a Release build because it's unused and the optimizer would realize that.
C# uses scoping for variables, and the scope of the variable number is the Main() method. If you define it inside the class instead, it'd be a class member and would be accessible also from the method Method(). As a general rule of thumb, though, always try to limit the scope of variables.
class Program
{
static int number = 5; // class member
public static void Main()
{
Method();
}
public static void Method()
{
number = 10; // no error anymore
int anotherNumber = 2;
}
}

variable is still on the stack so why can't I reach it here?
This argument hold as much water as "all variables are in memory so why can't I access from everywhere all variables, including variables from other programs, after all they are all on the same memory right?"
There are so many problems with what you propose. From encapsulation, to name pollution, to optimization, to security.
A local variable is just that: a local variable. It's for me, it's an implementation detail. The outside world should not know about it because since it's mine and I use it for my internal purposes I can change it or remove it at my will. With your proposal what? Now I can't change my own local variable because some function somewhere down the calling chain uses it. And why does it uses it? If I want to pass some information to the function I call then that should be done via parameters.
void foo() { int mine; bar(); }
void bar() { void baz(); }
void baz() { mine = 24; } // like wtf??
Besides how would you handle this situation:
void foo_1()
{
int mine; // I can name it mine because it's a local variable
bar();
}
void foo_2()
{
int mine; // I can also name it mine because it's a local variable
bar();
}
void foo_3()
{
bar();
}
void bar()
{
mine = 24; // ??????
}
In concussion to pass information from one function to another we use parameters, we don't pollute a fictional "global local namespace" because we are not savages.

Related

Unclear behavior by Garbage Collector while collecting instance properties or fields of reachable object

Till today I was thinking that members of reachable objects are also considered to be reachable.
But, today I found one behavior which creates a problem for us either when Optimize Code is checked or application is executed in Release Mode. It is clear that, release mode comes down to the code optimization as well. So, it seems code optimization is reason for this behavior.
Let's take a look to that code:
public class Demo
{
public Action myDelWithMethod = null;
public Demo()
{
myDelWithMethod = new Action(Method);
// ... Pass it to unmanaged library, which will save that delegate and execute during some lifetime
// Check whether object is alive or not after GC
var reference = new WeakReference(myDelWithMethod, false);
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
Console.WriteLine(reference.IsAlive);
// end - Check whether object is alive or not after GC
}
private void Method() { }
}
I simplified code a bit. Actually, we are using our special delegate, not Action. But the behavior is same. This code is written in mind with "members of reachable objects are also considered to be reachable". But, that delegate will be collected by GC asap. And we have to pass it to some unmanaged library, which will use it for some time.
You can test demo by just adding that line to the Main method:
var p = new Demo();
I can understand the reason of that optimization, but what is the recommended way to prevent such case without creating another function which will use that variable myDelWithMethod which will be called from some place? One, option I found that, it will work if I will set myDelWithMethod in the constructor like so:
myDelWithMethod = () => { };
Then, it won't be collected until owning instance is collected. It seems it can't optimize code in the same way, if lambda expression is setted as a value.
So, will be happy to hear your thoughts. Here are my questions:
Is it right that, members of reachable objects are also considered to
be reachable?
Why it is not collected in case of lambda expression?
Any recommended ways to prevent collection in such cases?
However strange this would sound, JIT is able to treat an object as unreachable even if the object's instance method is being executed - including constructors.
An example would be the following code:
static void Main(string[] args)
{
SomeClass sc = new SomeClass() { Field = new Random().Next() };
sc.DoSomethingElse();
}
class SomeClass
{
public int Field;
public void DoSomethingElse()
{
Console.WriteLine(this.Field.ToString());
// LINE 2: further code, possibly triggering GC
Console.WriteLine("Am I dead?");
}
~SomeClass()
{
Console.WriteLine("Killing...");
}
}
that may print:
615323
Killing...
Am I dead?
This is because of inlining and Eager Root Collection technique - DoSomethingElse method do not use any SomeClass fields, so SomeClass instance is no longer needed after LINE 2.
This happens to code in your constructor. After // ... Pass it to unmanaged library line your Demo instance becomes unreachable, thus its field myDelWithMethod. This answers the first question.
The case of empty lamba expression is different because in such case this lambda is cached in a static field, always reachable:
public class Demo
{
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static Action <>9__1_0;
internal void <.ctor>b__1_0()
{
}
}
public Action myDelWithMethod;
public Demo()
{
myDelWithMethod = (<>c.<>9__1_0 ?? (<>c.<>9__1_0 = new Action(<>c.<>9.<.ctor>b__1_0)));
}
}
Regarding recommended ways in such scenarios, you need to make sure Demo has lifetime long enough to cover all unmanaged code execution. This really depends on your code architecture. You may make Demo static, or use it in a controlled scope related to the unmanaged code scope. It really depends.

Static variable inside class

I am much confused about static variable actually i am executing below program.
class ABC
{
public static int prop { get; set; }
const int i =5;
static int j;
public ABC()
{
prop = 8;
j = 9;
Console.WriteLine("Under ABC class's constructor.");
}
public int getValue()
{
j = 6;
prop = 89;
return j;
}
}
class Program
{
static void Main(string[] args)
{
ABC obj = new ABC();
Console.WriteLine(obj.getValue());
//Console.WriteLine(ABC.j);
Console.ReadLine();
}
}
And its executing without any compile or run time error.
I have following confusions.
can we assign static variable/property inside the non static constructor?
can we assign static variable/property inside the instance method also?
If we can do assignment in above two cases for static variable/property then what is the use of static constructor?
Finally what are the locations inside a class where we can assign/initialize a static variable/property?
can we assign static variable/property inside the non static
constructor?
Yes.
can we assign static variable/property inside the instance method
also?
Yes.
If we can do assignment in above two cases for static
variable/property then what is the use of static constructor?
A static constructor is also called a type initializer. It is responsible for initializing the type it is defined in. You may use it to perform calculations that can be done upfront and are the same for all instances of that type. You'll therefore save some execution time when creating an instance because the calculation has already been done by the type initializer. Note that the type initializer runs before the type is used the first time. So you cannot deterministically tell when it actually runs. You can also not catch exceptions thrown by it because you don't actually invoke the type initializer yourself. You therefore need to be careful not to put error prone operations inside type initializers (f.e. do not do IO operations inside them).
Finally what are the locations inside a class where we can
assign/initialize a static variable/property?
From anywhere. Note that, even across threads, you can read and write to a static member from anywhere. This makes it very hard to find bugs that may occure due to a programm mutation a static somewhere in memory.
As a side note: Try to avoid having mutable static memory to keep your application simpler. If you really need to ... you should consider locking access to the static resource to prevent data races.

Overloading in local methods and lambda

static void Main() {
void TestLocal() => TestLocal("arg");
TestLocal("arg");
}
static void TestLocal(string argument) {
}
In this example, local function has the same name as another method, which I want to overload. But this method is invisible from inside of this function, and even from inside of Main(). The same is for lambdas:
static void Main() {
Action TestLambda = () => TestLambda("arg");
}
static void TestLambda(string argument) {
}
I understand, why lambda hides outer method - because it is a local variable, and local variables always work this way. But I don't see any reason for local functions hide and not overload outer methods - it could be very useful for reducing amout of arguments in local scope, doing some kind of carrying.
Why local functions hide methods?
EDIT:
I can imagine an example where it gets complicated
void Bar(short arg) {
Console.WriteLine("short");
}
void Bar(byte arg) {
Console.WriteLine("byte");
}
void Test() {
void Bar(int arg) {
Console.WriteLine("int");
}
Bar(0);
}
It was already complicated enough with argument type resolution. If they added overloading to local methods, it would be one more stupid task for job interviews and one more huge task for compiler makers. And there are also virtual and new methods...
Why local functions hide methods?
Basically it's introducing the method name into the declaration space inside the method. Within that declaration space, the name only refers to the local method... just as it does for a local variable. I think that's reasonably consistent with the way that names introduced into methods have always worked.
I'd personally advise against trying to do this anyway, as it'll cause confusion, but if you really need to refer to the class method, just make it explicit:
ClassName.TestLocal("arg");
What I do think could be fixed is that local methods can't be overloaded between themselves. You can't write:
void Foo()
{
void Method(int x) {}
void Method(string y) {}
}
This is for a related reason - a method's declaration space can't include the same name twice, whereas a class's declaration space can do so, in terms of method overloading. Maybe the rules will be loosened around this...

C# Variable Scope stopping me in my tracks

I'm fairly new to programming. The the constant issue I keep facing when I try anything for myself in C based languages is the scope.
Is there any way to use or modify a variable from within a different method or class? Is there also a way to do this without creating a new intance of a class or object? It seems to wipe the slate clean every time.
Example, I'm setting up a console text game, and I want a different background message to write to the console at certain intervals.
public static void OnTimedEvent(object scource, ElapsedEventArgs e)
{
if(Exposition.Narration == 1)
{
Console.WriteLine("The bar is hot and muggy");
}
if (Exposition.Narration == 2)
{
Console.WriteLine("You see someone stealing beer from the counter");
}
if (Exposition.Narration == 3)
{
Console.WriteLine("There is a strange smell here");
}
}
But I have no way of making different messages play. If I create the variable from within the method it will send that variable to its defult everytime it runs. If I create a new instance of an object or a class, it sends things back to the defult as well. Also, I can't modify a single class when I'm creating new instances of them all the time.
That's just one example of where its been a problem. Is there a way to have a varable with a broader scope? Or am I thinking about this the wrong way?
edit:
To put it simply can I read or change a variable from within a different method or class?
using System;
namespace Examp
{
class Program
{
public static void Main(string[] args)
{
int number = 2;
other();
}
public static void other()
{
if (Main.number == 2)
{
number = 3
}
}
}
}
While I don't think I understood completely your question, you can see here some ways to make a variable "persist" outside a method:
Static variables
Static variables are something like a global variable. You can see them through all the program if you set them as public (if you set them as internal, it's different).
A static variable can be defined as:
class MyClass
{
static int MyVariable = 4;
}
....somewhere...
void MyMethod()
{
MyClass.MyVariable = 234;
}
As you can see, you can access them anywhere.
Variables on heap
If you create an object with new operator, if you keep reference to that object, every modify you do on it, it reflects on all references to that object that you have. For example
class MyClass
{
int X;
}
static class Program
{
static void Main(string args[])
{
MyClass a = new MyClass();
a.X = 40;
Method1(a);
Method2(a);
Console.WriteLine(a.X.ToString()); // This will print 32
}
static void Method1(MyClass c)
{
c.X = 10;
}
static void Method2(MyClass c)
{
c.X = 32;
}
}
You can even use refs to edit your variables inside a method
Basically you misunderstood the concept of "scope", because you question is "which variable types exist" (global/static/local etc.). What you would like to know about scope is this: A local variable exists only within { } where it's defined.
I hope this gives you some suggestion. The answer is definitely not complete but can give you an idea.
Try to be more specific so I can change my answer.
Answer to edit 1:
No you can't change a variable in the way you want, you must add it to the class (Program in this case), try adding:
class Program
{
static int number;
....
}
Obviusly you should remove the one inside the Main method.
Also note that int can't be modified (except without a ref) inside a function if you pass them as parameters because they are copied.
The reason is quite simple: a reference to a Class instance is (at least) the same size as an int (if we are speaking about 32/64 bit systems), so it takes the same time copying it or referencing it.
You can return a value from a method after you have done your calculations if you want, like this:
int x = 3;
x = DoSomethingWithX(x);
int DoSomethingWithX(int x)
{
x += 30;
}
Class access modifiers allow you to control the members that you want the class to expose to other classes. Furthermore, static class with singleton pattern allow use to reuse the same instance across your application.
Looking at your example, it appears that you are simply trying to read the class member, hence a public property in your class should suffice. The instance of this class can be passed while initializing the class in which your OnTimedEvent method is present (this method should be changed to an instance method to access non static members of the your class).
For example,
class MyClass
{
private Exposition exposition;
// Option 1: Use parametrized constructor
// Pass the instance reference of the other class while
// constructing the object
public MyClass(Exposition exposition)
{
this.exposition = exposition;
}
// Option 2: Use an initialize method
public void Initialize(Exposition exposition)
{
this.exposition = exposition;
}
// Remove static to access instance members
public void OnTimedEvent(object scource, ElapsedEventArgs e)
{
// Better to use an enumeration/switch instead of magic constants
switch(exposition.Narration)
{
case HotAndMuggy:
Console.WriteLine("The bar is hot and muggy");;
break;
...
}
}
// Option 3: Use static properties of the Exposition class
// Note this approach should be used only if your application demands
// only one instance of the class to be created
public static void OnTimedEvent_Static(object scource, ElapsedEventArgs e)
{
// Better to use an enumeration/switch instead of magic constants
switch(Exposition.Narration)
{
case HotAndMuggy:
Console.WriteLine("The bar is hot and muggy");;
break;
...
}
}
}

Does there exist a keyword in C# that would make local variables persist across multiple calls?

That is, in C, we can define a function like:
func(){
static int foo = 1;
foo++;
return foo;
}
and it will return a higher number every time it is called.
Is there an equivalent keyword in C#?
No, there's no such thing in C#. All state that you want to persist across multiple method calls has to be in fields, either instance or static.
Except... if you capture the variable in a lambda expression or something like that. For example:
public Func<int> GetCounter()
{
int count = 0;
return () => count++;
}
Now you can use:
Func<int> counter = GetCounter();
Console.WriteLine(counter()); // Prints 0
Console.WriteLine(counter()); // Prints 1
Console.WriteLine(counter()); // Prints 2
Console.WriteLine(counter()); // Prints 3
Now of course you're only calling GetCounter() once, but that "local variable" is certainly living on well beyond the lifetime you might have expected...
That may or may not be any use to you - it depends on what you're doing. But most of the time it really does make sense for an object to have its state in normal fields.
You'd have to create a static or instance member variable of the class the method is in.
public class Foo
{
static int _bar = 1;
public int Bar()
{
return ++_bar;
}
}

Categories

Resources