How to access locals through stack trace? (Mimicking dynamic scope)

.net, c#, dynamic-languages, scope

Solution

This isn't possible. In the compiled .NET code (intermediate language), variables are represented simply as indices on the stack. For example the `ldloc` instruction, which loads a value of a variable takes only an `unsigned int16` value as the parameter. There may be some way to do this for applications compiled in debug mode (after all, when debugging application, Visual Studio does that), but it cannot work in general.

In Phalanger (PHP compiler for .NET, which I'm partly involved in), this had to be somehow solved, because PHP language has `eval` (it doesn't need to provide dynamic scoping, but it needs to access variables by name). So, Phalanger detects if a function contains any use of `eval` and if it does, it stores all variables in `Dictionary<string, object>`, which is then passed to the `eval` function (so that it can read variables by their name). I'm afraid this is the only way to do this...

Problem

Background Even though it's possible to compile C# code at runtime, it's impossible to include and run the generated code in the current scope. Instead all variables have to be passed as explicit parameters. Compared with dynamic programming languages like Python, one could never truly replicate the complete behaviour of `eval` (as in this example). ``` x = 42 print(eval("x + 1")) # Prints 43 ``` The question So my question is (regardless if it's actually useful ;)) whether it's possible to mimic dynamic scope in .NET through the use of reflection. Since .NET provides us with the `Diagnostics.StackTrace` class which allows us to inspect the calling methods, this question boils down to the following: (How) is it possible to reliably access the locals of calling methods? Does the stack trace provide us with enough information to compute the memory offsets or are such things forbidden in managed code anyway? Is such code somehow possible? ``` void Foo() { int x = 42; Console.WriteLine(Bar()); } int Bar() { return (int)(DynamicScope.Resolve("x")); // Will access Foo's x = 42 } ```

Original source