admin管理员组文章数量:1389681
I've read that due to how the scope chain works in javascript, if we wish to refer to a variable V within a function F that is not declared within the F's scope, it is beneficial (yes in terms of performance) to declare a local variable V2 in F that references V, then accessing the object referenced by V through V2.
i'm wondering if this concept applies to the closures in C# and VB (accessing local variables in functions through lambdas)
Public Shared Function Example()
Dim a = 1
Dim b = New Object
Return Sub()
'when we use the variables a and b from here does it have to "go up the scope chain"
End Sub
End Function
btw i would prefer if the answer isn't premature optimization is the root of all evil
I've read that due to how the scope chain works in javascript, if we wish to refer to a variable V within a function F that is not declared within the F's scope, it is beneficial (yes in terms of performance) to declare a local variable V2 in F that references V, then accessing the object referenced by V through V2.
i'm wondering if this concept applies to the closures in C# and VB (accessing local variables in functions through lambdas)
Public Shared Function Example()
Dim a = 1
Dim b = New Object
Return Sub()
'when we use the variables a and b from here does it have to "go up the scope chain"
End Sub
End Function
btw i would prefer if the answer isn't premature optimization is the root of all evil
Share Improve this question edited May 7, 2011 at 21:11 Pacerier asked May 7, 2011 at 20:24 PacerierPacerier 89.9k111 gold badges385 silver badges645 bronze badges 8- Are you talking about issues as in performance, or...? – Matti Virkkunen Commented May 7, 2011 at 20:30
- code example, please. Also, what do you mean by, "it is beneficial"? what are the benefits you are referring to? – Cheeso Commented May 7, 2011 at 20:34
- @Matti Virkkunen i've edited the question – Pacerier Commented May 7, 2011 at 21:11
- 1 now that you've updated your question: i have no idea, but it should be easy for you to test. – Cheeso Commented May 7, 2011 at 21:15
-
The scope chain in JavaScript is a specification abstraction. In EcmaScript 5 strict mode, where
with
is not allowed, andeval("var x;")
cannot add bindings to the local environment, and in regular EcmaScript functions that do not usewith
oreval
, there is no need for an interpreter to walk the scope chain to find a local variable binding. It was only the (perceived) need to handle aliasedeval
that caused this inefficiency in older interpreters. – Mike Samuel Commented May 7, 2011 at 21:50
3 Answers
Reset to default 7Short answer: no. .NET doesn't need to walk up the scope chain to find the variables.
Long answer:
Start with this example:
static Func<string> CaptureArgs(int a, int b)
{
return () => String.Format("a = {0}, b = {1}", a, b);
}
static void Main(string[] args)
{
Func<string> f = CaptureArgs(5, 10);
Console.WriteLine("f(): {0}", f());
// prints f(): a = 5, b = 10
}
In the CaptureArgs
method, a
and b
exist on the stack. Intuitively, if we reference the variables in an anonymous function, return the function and popping the stack frame should remove a
and b
from memory. (This is called the upward funargs problem).
C# doesn't suffer from the upwards funargs problem because, behind the scenes, an anonymous function is just fancy syntax sugar over a piler-generated class. The C# code above turns into:
private sealed class <>c__DisplayClass1
{
// Fields
public int a;
public int b;
// Methods
public string <CaptureArgs>b__0()
{
return string.Format("a = {0}, b = {1}", this.a, this.b);
}
}
The piler creates and returns a new instance of <>c__DisplayClass1
, initializes its a
and b
fields from the a
and b
passed into the CaptureArgs
method (this effectively copies a
and b
from the stack to fields existing on the heap), and returns it to the caller. Calling f()
is really a call to <>c__DisplayClass1.<CaptureArgs>b__0()
.
Since the a
and b
referenced in <CaptureArgs>b__0
are vanilla fields, they can be referenced directly by the delegate, they don't require any special sort of scope chaining rules.
If I understand it correctly, the problem with JavaScript is following: When you access a variable in a (deeply) nested scope, the runtime needs to walk through all parent scopes to locate the variable.
Lambdas in C# or Visual Basic do not suffer from this issue.
In VB or C#, the piler knows exactly which variable are you referring to in a lambda function, so it can create a direct reference to the variable. The only difference is that captured variables (those accessed from nested scope) have to be turned from a local variable into a field (in some object, also called a closure).
To add an example - say you write something (crazy) like this:
Func<Func<int>> Foo() {
int x = 10;
return () => {
x++;
return () => x;
}
}
This is a bit silly, but it demonstrates nested scoping. The variable is declared in one scope, set in a nested scope and read in an even deeper scope. The piler will produce something like this:
class Closure {
public Closure(int x) { this.x = x; }
public int x;
public Func<int> Nested1() {
x++;
return Func<int>(Nested2);
}
public int Nested2() { return x; }
}
Func<Func<int>> Foo() {
var clo = new Closure(10);
return Func<Func<int>>(clo.Nested1);
}
As you can see - there is not walking through a chain of scopes. Each time you access the variable x
, the runtime directly accesses some location in memory (allocated on the heap, instead of a stack).
Short answer: No.
C# closures are implemented in a static fashion (closed over variables are explicitly known and bound) and does not traverse through a [[scope chain]]
, as in Javascript.
Run some tests to put your mind at ease, then just don't worry about it ;-)
Happy coding.
本文标签: does C and VB lambdas have **scope chain** issues similar to javascriptStack Overflow
版权声明:本文标题:does C# and VB lambdas have **scope chain** issues similar to javascript? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744459812a2607181.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论