4 ms·
What does this have to do with values or references? They are orthogonal to scopes, and this example is an issue of scoping. A closure finds free variables in o
by jhgb 5y ago
What does this have to do with values or references? They are orthogonal to scopes, and this example is an issue of scoping. A closure finds free variables in one of its enclosing scopes. If the for loop creates one mutable binding for its control variable, even multiple closures created within the loop's body can all see this single mutable binding because they all share the single environment with this mutable binding in which all of them were created, so they can all observe this binding mutating over time. There are no "arguments by value or reference" because the closure in the example is nullary -- it has no arguments at all.
- ImprobableTruth 5y agoThey're talking about capture by value or reference. If you use capture by value, created closures will use the value of captured variables at the time the closure is generated. e.g. in C++, where one has to make capture by reference explicit int i = 0; auto f = [x = i, &y = i] { //x captures i by value, y by reference std::cout << "Value:" << x << ", Reference:" << y; }; i++; f(); will print out "Value: 0, Reference: 1".
- jhgb 5y agoI'm not sure you can call this "a closure". That term has a rather specific meaning related to lexical scoping which simply doesn't deal with copies or references or anything of the kind. There's no "capture by value or reference" since it's not a copy of a value, or even a reference to it -- it's one and the same variable binding inside and outside of the closure (whereas a reference would be another variable name referring to the same value, or at least a differently scoped variable of the same name referring to the same value, but that's not lexical scoping anymore). To put it bluntly, C++ is faking closures, since without subjecting environments to GC or refcounting, it can't delete the shared environments at just the right time. They just jumped on the bandwagon of closures being fashionable nowadays and tried to emulate closures as closely as possible by constructing artificial automatically generated objects in the background using some syntactic sugar without breaking the existing language.
- ImprobableTruth 5y agoI don't really understand your objection. How is >at least a differently scoped variable of the same name referring to the same value, but that's not lexical scoping anymore not lexical scoping? That's literally just how closures work under the hood. And that's exactly why closures have to deal with references (or copies) - every implementation of them is a function pointer and a record for the lexical environment, the latter of which requires that at closure creation time the relevant bindings are captured, either by creating a reference or making a copy. I also don't understand why C++'s (or Rust's) closures would be 'fake'. If you capture by reference, they work exactly like the closures of other languages. Not having a GC just means you have to be wary of lifetimes. If you use a reference counting pointer (/some other GC'd pointer) you literally have the same closures as other languages.
- jhgb 5y ago> How is ... not lexical scoping? That's literally just how closures work under the hood. In the presence of references in the language, these two cases may be observationally indistinguishable (maybe, I'm not a C++ guru?) but they're still different language features. Lexical scoping does not require taking a reference. > And that's exactly why closures have to deal with references (or copies) No, they don't. They deal with bindings. References are either an explicit thing you create (as in, int &b=a; or such), or a parameter passing mechanism...but a free variable is neither (it's not a parameter to the closure in any case), and it exists even in languages with no notion of references whatsoever, such as for example Scheme. > I also don't understand why C++'s (or Rust's) closures would be 'fake'. If you capture by reference, they work exactly like the closures of other languages. Not having a GC just means you have to be wary of lifetimes. Yeah, and that's at least one of the things that make it fake. Why would you have to be wary about lifetimes? Closures in languages that support them Just Work(TM).
- CornCobs 5y agoWhat do you mean by "languages with no notion of references whatever"? At least in Scheme I think references are a pretty immediately obvious feature. It's not like every assignment does a deep copy, nor does free variable capture in closures. The moment you do stuff with set-car! and friends you are very explicitly working with references