0

Is capture by value (x below) an early binding and capture by reference (y below) a late binding in C++ lambdas, or are they both early bindings—the first by value and the second by reference?

#include <iostream>


int main() {
    auto x = 0, y = 0;
    auto lambda = [x, &y]() { std::cout << x << ' ' << y; };
    x = 1, y = 1;
    lambda();  // outputs: 0 1
    return 0;
}
3
  • 3
    Early and late binding are used almost exclusively for method call semantics. As such, the question doesn't really make sense. Commented Aug 6, 2020 at 19:35
  • @SebastianRedl Could you share some references supporting this?
    – Géry Ogam
    Commented Aug 6, 2020 at 20:37
  • 1
    @SebastianRedl Early and late binding is relevant for anything that has a name in your code whether it’s method, free function or data. The fact that the term is mostly associated with functions and methods and often in an object oriented context doesn’t invalidate this question at all. See this nice overview of the different concepts relating to binding: cs.iusb.edu/~dvrajito/teach/c311/c311_3_scope.html
    – Christophe
    Commented Aug 7, 2020 at 8:31

1 Answer 1

4

The lambda defines a closure, which is an anonymous function together with an environment composed of captured variables.

The binding of captured variables happens at the moment the lambda is defined and uses the variables of the scope in which it was defined. This is early binding. As you said, early binding of a value and of a reference in your example.

As a consequence of early binding, if you would enclose your lambda call in its own scope with another x and y variable, the capture would still use the original x value and the reference to the y of the scope of the definition:

#include <iostream>


int main() {
    auto x = 0, y = 0;
    auto lambda = [x, &y]() { std::cout << x << ' ' << y; };
    x = 1, y = 1;
    {
        auto x = 27, y = 2;
        lambda();  // still outputs: 0 1
    }
    return 0;
}

Online demo

Another consequence is that if the variable captured by reference no longer exists when you invoke the lambda you have undefined behaviour.

Late binding would work differently: the capture would not bind to y in main(). It would bind to an identifier corresponding to y. The binding would be done when the lambda would be invoked. In my example, the binding would be done with the inner y, and the output would be 0 2.

17
  • With your example it is crystal clear Christophe, thanks for this amazing answer. Not only did you answer my question, but also the subsidiary answers that I had in mind. I still have a few more though: 1. If early binding is binding by value or binding by reference, could we say that late binding is binding by name. 2. The following Python code uses late binding, right? f = lambda: x; x = 1; print(f())
    – Géry Ogam
    Commented Aug 7, 2020 at 0:26
  • @Maggyero: "If early binding is binding by value or binding by reference, could we say that late binding is binding by name." I think you misunderstood his point. Both of those are "early binding" but only by-default; the early/late binding nomenclature simply isn't meaningful in this context. The use of a reference is not "early binding"; a function which takes a reference to a polymorphic base class would represent "late binding". Commented Aug 7, 2020 at 3:56
  • 1
    @Maggyero I didn’t forget 2, but I’m not a Python guru and not sure to fully master its semantics when it comes to subtle subjects. My inderstanding from this is that free variables are variables late binding and binding by name. In C++ every variable is bound at compile time and there is no real equivalent of a free variable. You’d have to emulate this using some symbol table (e.g. a map).
    – Christophe
    Commented Aug 7, 2020 at 11:54
  • 1
    @Maggyero when I learned compiler design, JIT compiler didn’t exist. The definition of early and late binding were straightforward : if the compiler couldn’t bind the name at compilation, it was late. But now, JIT compilers make the frontier more difficult to grasp: what is done by the jit compiler? and what is done by the runtime environment? So it needs implementation (dependent?) information to decide.
    – Christophe
    Commented Aug 9, 2020 at 19:37
  • 1
    @Maggyero Interesting question; My knowledge of JavaScript is rather superficial, but after studying the specs about bindings, experimenting a little, and lloking for confirmation in at least one article, I think I have provided a decent answer.
    – Christophe
    Commented Aug 11, 2020 at 21:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.