Best Way to Avoid Capturing a Copy of the Value in Closure

Best way to avoid capturing a copy of the value in closure

I'm wondering what is the best way here to avoid capturing a copy of an ivar.

That is a misconception. You cannot "capture an ivar" in this way. What you are capturing is self! That is exactly why Swift forces you to say self, so that you understand this fact. Thus, it makes a difference what kind of thing self is. And that is why it matters whether self is a struct or a class. The class instance is mutable in place; the struct instance is not, so a copy is taken at the time of capture and that copy persists independently.

However, you can capture a simple Int (i.e. not an ivar), and when you do, you get the result you expect:

var i = 0
struct Foo {
func delayedPrint() {
dispatch_async(dispatch_get_main_queue(), {
println(i) // 1
})
}
func foo() {
delayedPrint()
i++
}
}

Now let's talk about the second puzzle that you pose. Here's a rewrite, to clarify what the puzzle is:

func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
struct Foo {
var i = 0
mutating func foo() {
delay(0.5) {
println("From foo: \(self.i)") // 1
}
bar(2)
i++
}
func bar(d:Double) {
delay(d) {
println("from bar: \(self.i)") // 0
}
}
}

I'll test it like this:

var a = Foo()
a.foo()
a.bar(1)

The console shows:

From foo: 1 [after half a second]
from bar: 1 [after 1 second]
from bar: 0 [after 2 seconds]

So how can bar be called the second time 1 second later, yet show a value of self.i that is earlier? And why does foo behave differently?

The answer has to do with the fact that everything is happening inside functions - including the definitions of the anonymous functions. The code has to run at some point. Until then, the anonymous function is not defined.

  1. First let's consider a.bar(1). This causes bar to run and to define the anonymous function which will capture self. But this happens after we have called foo and incremented i. Thus, the self captured at this time has an incremented i.

  2. Next let's consider what happens when foo calls bar. It does this before incrementing i. So now bar runs and the anonymous function is defined, and captures self with i still set at 0. The fact that this result arrives into the console two seconds later is irrelevant; what is important is when the capture took place.

  3. Finally we come to the surprising case of the anonymous function inside foo. Clearly, the presence of the i++ inside foo make all the difference. Why? Well, when foo runs, it defines an anonymous function that captures self. But this self has also been captured inside foo itself for the purposes of saying i++ — which is really self.i++. Thus, the change on self performed by i++ is seen by this anonymous function as well, because they are looking at the same self.

    In other words, I'm suggesting that you have hit the Mysterious Edge Case of the anonymous function defined within a function that itself mutates self. (I don't know if I think this a bug or not; I'm going to submit it to dev forum and see what they think.)

How closure captures value type?

Can somebody explain how closure captures x in this case and keeps it in memory.

There isn't really a "how". That is what a closure is. It does capture x and keep it in memory. Basically, your x does not die when the local reference goes out of scope, because the closure has captured it and lives on; thus x still lives after foo has run, off in an invisible "closure capture" space belonging to this closure, for as long as the closure itself persists.

The ability of closures to do that is what makes a closure a closure.

A feature of this ability that your example doesn't get at is that the captured reference is still writable (because you said var). For example:

var cl: (() -> ())!
func foo() {
var x = 20
cl = {
print(x)
x += 1
}

}
foo()
cl() // prints 20
cl() // prints 21

We are thus able to maintain state off in the closure-capture world.

Another thing to notice (I suppose you know this) is that if this had not been an automatic variable that goes out of scope, writing to it would affect the original — the reference is direct. Thus:

var cl: (() -> ())!
var x = 20
func foo() {
cl = {
print(x)
x += 1
}

}
foo()
cl() // prints 20
cl() // prints 21
print(x) // 22

How closure captures values in Swift?

From Swift Programming Guide - Closures

A closure can capture constants and variables from the surrounding context in which it’s defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.

A closure captures variables, not the contents of variables. When we are talking about local variables in a function (which are normally allocated on stack), it makes sure they are accessible even when the function exits and other local variables are deallocated, therefore we can do things like this:

func myFunc() {
var array: [Int] = []

DispatchQueue.main.async {
// executed when myFunc has already returned!
array.append(10)
}
}

Your example is similar. The closure captures the variable. This is a variable on module level, therefore its scope always exists. When you reassign its value, it will affect the value read inside the closure.

Or, in other words, the closure will be equivalent to:

var closure = {
print(CurrentModule.element?.name ?? "default value")
}

where CurrentModule is the name of your main module (which is usually the name of your project).

To prevent this behavior and capture the value of the variable instead, we can use closure capture list. Unfortunately, the official documentation does not properly explain what exactly is a capture list. Basically, using a capture list you declare variables local to the closure using values that are available when the closure is created.

For example:

var closure = { [capturedElement = element] in
print(capturedElement?.name ?? "default value")
}

This will create a new variable capturedElement inside the closure, with the current value of variable element.

Of course, usually we just write:

var closure = { [element] in
print(element?.name ?? "default value")
}

which is a shorthand for [element = element].

Understanding variable capture by closures in Javascript/Node

I don't have a handy reference. But the bottom line is: In the first, you're explicitly passing in i to an anonymous function, which creates a new scope. You are not creating a new scope for either i or j in the second. Also, JavaScript always captures variables, not values. So you would be able to modify i too.

The JavaScript var keyword has function scope, not block scope. So a for loop does not create a scope.

As a note, the non-standard let keyword has local scope.

Avoiding escaped values in closures

You can just do this:

for(int i=0; i<10; i++)
{
int number = i;
MyApi.AddLazyCreate(() => new foo(/*other params*/ number));
}

This will cause it to capture a different number on each iteration of the loop.

C++ confusing closure captures [v] vs [v = v]

I don't disagree with 康桓瑋's answer, but I found it a little hard to follow, so let me explain it with a different example. Consider the following program:

#include <functional>
#include <iostream>
#include <typeinfo>
#include <type_traits>

struct tracer {
tracer() { std::cout << "default constructed\n"; }
tracer(const tracer &) { std::cout << "copy constructed\n"; }
tracer(tracer &&) { std::cout << "move constructed\n"; }
template<typename T> tracer(T &&t) {
if constexpr (std::is_same_v<T, const tracer>)
std::cout << "template constructed (const rvalue)\n";
else if constexpr (std::is_same_v<T, tracer&>)
std::cout << "template constructed (lvalue)\n";
else
std::cout << "template constructed (other ["
<< typeid(T).name() << "])\n";
}
};

int
main()
{
using fn_t = std::function<void()>;

const tracer t;
std::cout << "==== value capture ====\n";
fn_t([t]() {});
std::cout << "==== init capture ====\n";
fn_t([t = t]() {});
}

When run, this program outputs the following:

default constructed
==== value capture ====
copy constructed
template constructed (const rvalue)
==== init capture ====
copy constructed
move constructed

So what's going on here? First, note in both cases, the compiler must materialize a temporary lambda object to pass into the constructor for fn_t. Then, the constructor of fn_t must make a copy of the lambda object to hold on to it. (Since in general the std::function may outlive the lambda that was passed in to its constructor, it cannot retain the lambda by reference only.)

In the first case (value capture), the type of the captured t is exactly the type of t, namely const tracer. So you can think of the unnamed type of the lambda object as some kind of compiler-defined struct that contains a field of type const tracer. Let's give this structure a fake name of LAMBDA_T. So the argument to the constructor to fn_t is of type LAMBDA_T&&, and an expression that accesses the field inside is consequently of type const tracer&&, which matches the template constructor's forwarding reference better than the actual copy constructor. (In overload resolution rvalues prefer binding to rvalue references over binding to const lvalue references when both are available.)

In the second case (init capture), the type of the captured t = t is equivalent to the type of tnew in a declaration like auto tnew = t, namely tracer. So now the field in our internal LAMBDA_T structure is going to be of type tracer rather than const tracer, and when an argument of type LAMBDA_T&& to fn_t's constructor must be move-copied, the compiler will choose tracer's normal move constructor for moving that field.

Detailed Explanation of Variable Capture in Closures

  1. Is tricky. Will come onto it in a minute.
  2. There's no difference - in both cases, it's the variable itself which is captured.
  3. Nope, no boxing occurs.

It's probably easiest to demonstrate how the capturing works via an example...

Here's some code using a lambda expression which captures a single variable:

using System;

class Test
{
static void Main()
{
Action action = CreateShowAndIncrementAction();
action();
action();
}

static Action CreateShowAndIncrementAction()
{
Random rng = new Random();
int counter = rng.Next(10);
Console.WriteLine("Initial value for counter: {0}", counter);
return () =>
{
Console.WriteLine(counter);
counter++;
};
}
}

Now here's what the compiler's doing for you - except that it would use "unspeakable" names which couldn't really occur in C#.

using System;

class Test
{
static void Main()
{
Action action = CreateShowAndIncrementAction();
action();
action();
}

static Action CreateShowAndIncrementAction()
{
ActionHelper helper = new ActionHelper();
Random rng = new Random();
helper.counter = rng.Next(10);
Console.WriteLine("Initial value for counter: {0}", helper.counter);

// Converts method group to a delegate, whose target will be a
// reference to the instance of ActionHelper
return helper.DoAction;
}

class ActionHelper
{
// Just for simplicity, make it public. I don't know if the
// C# compiler really does.
public int counter;

public void DoAction()
{
Console.WriteLine(counter);
counter++;
}
}
}

If you capture variables declared in a loop, you'd end up with a new instance of ActionHelper for each iteration of the loop - so you'd effectively capture different "instances" of the variables.

It gets more complicated when you capture variables from different scopes... let me know if you really want that sort of level of detail, or you could just write some code, decompile it in Reflector and follow it through :)

Note how:

  • There's no boxing involved
  • There are no pointers involved, or any other unsafe code

EDIT: Here's an example of two delegates sharing a variable. One delegate shows the current value of counter, the other increments it:

using System;

class Program
{
static void Main(string[] args)
{
var tuple = CreateShowAndIncrementActions();
var show = tuple.Item1;
var increment = tuple.Item2;

show(); // Prints 0
show(); // Still prints 0
increment();
show(); // Now prints 1
}

static Tuple<Action, Action> CreateShowAndIncrementActions()
{
int counter = 0;
Action show = () => { Console.WriteLine(counter); };
Action increment = () => { counter++; };
return Tuple.Create(show, increment);
}
}

... and the expansion:

using System;

class Program
{
static void Main(string[] args)
{
var tuple = CreateShowAndIncrementActions();
var show = tuple.Item1;
var increment = tuple.Item2;

show(); // Prints 0
show(); // Still prints 0
increment();
show(); // Now prints 1
}

static Tuple<Action, Action> CreateShowAndIncrementActions()
{
ActionHelper helper = new ActionHelper();
helper.counter = 0;
Action show = helper.Show;
Action increment = helper.Increment;
return Tuple.Create(show, increment);
}

class ActionHelper
{
public int counter;

public void Show()
{
Console.WriteLine(counter);
}

public void Increment()
{
counter++;
}
}
}

How does closures capture data?

You should first search for the difference between strong, weak, and unowned. There are PLENTY of answers here on SO about it.

Anyways, in this specific case:

Your closure has this code:

[unowned self,ac]

This is called a "capture list". It indicates the things that should be "captured" by value WHEN THE BLOCK is created. (if you don't specify them here, and you change the value somewhere after the block, the value inside the block would also be changed).

The reason why self is unowned and doesn't require to be deallocated is because unowned means:

"Don't worry about memory management for this variable, it will ALWAYS
have a value for the duration of my closure"

So, going back to unowned self, the reason you should declare weak or unowned the self variable from a closure is because if not you would create a retain cycle. Things can't be deallocated as long as something is referencing them. So in this case, your TableViewController is keeping your closure alive, and your closure is keeping your TableViewController alive. So because they are referencing each other none of them can get deallocated properly. -> Memory Leak

So we can conclude that self has to either be weak or unowned. For all intents and purposes in this example they are exactly the same. They both serve the purpose of "breaking the retain cycle" by removing the ability of the closure to keep self alive. So who will dealloc self you ask? your closure doesn't care. But think outside your closure. Your closure is being called by your TableViewController, so since there's no weird things going on here we can safely assume that, if there is an alert being shown it must definitively be shown over your TableViewController. So once you dismiss the alert or whatever, your TableViewController will keep working as usual. One you dismiss your TableViewController though, self WILL be deallocated (since the closure is referencing it as unowned), but by this point there is no way the alert is being shown. If you however do some weird things that make your TableViewController be dismissed WHILE the alert is still being shown, then once the user "submits" your app will crash. BECAUSE by declaring your variable unowned you basically made a promise to your closure that it wouldn't have to worry about the self entity, as it would always exist as long as your closure was alive.



Related Topics



Leave a reply



Submit