Creating a mutating closure

in C++ I can write

auto f = [y = 4] () mutable { return y++; };

can I do this in swift? the obvious syntax is something like:

var f = { mutating [y = 4] in y += 1; return y }

but this does not work, there seems to be no place to put declaration-modifiers here.

In C++ the mutable there causes the resulting closure to look like:

struct Anon {
   int y = 0;
   int operator ()() {
      return y+=1;
   }
};

instead of

struct Anon {
   int y = 0;
   int operator ()() const {
      return y+=1; /* error, this is const* Anon */
   }
};

This came up when writing swiftUI views using ViewBuilders, I wanted to be able to add state variables in some subtree.

1 Like

You want inout:

let f: (inout Int) -> Void = { y in y += 1 }
var x = 0
f(&x)

EDIT: Huh, looks like the compiler can infer inoutness. Didn't know that. This works too:

let f = { y in y += 1 }

The equivalent in Swift is just to capture a var:

  var y = 4
  let f = { y += 1; return y }
5 Likes

Whenever I hear a "can swift do this like c++" I usually recommend reading through one of the essays @Douglas_Gregor posts on this topic.

3 Likes
let f: (inout Int) -> Void = { y in y += 1 }
var x = 0
f(&x)

This is not quite what I want. The C++ lambda in question doesn't have any parameters, it has one capture only.

What I want is for this to be inout. Which is not the same as capturing "this" by reference, in that case the captured "this" is mutable but the lambda context itself is still immutable.

2 Likes

Are you looking for a feature demonstrated by the second example in this answer? I don't think Swift supports it (because I have never read about it). Just curious, why does Swift's capturing by reference not work in your case?

In SwiftUI you can use @State property wrapper for this purpose:

struct MyView: View {
  @State var foo: Int = 4
}

Can you please provide a code snippet and the problem you try to solve. It seems there is a wrong focus in this thread. While it is interesting to do a 'closure that mutate value-type instance' on its own, it seems that this is a wrong direction of solving your concrete SwiftUI task.

5 Likes