Capturing structs by reference


(Tyler Cloutier) #1

The Swift Programming Language book states:

"Reference counting only applies to instances of classes. Structures and enumerations are value types, not reference types, and are not stored and passed by reference.”

However consider the following example.

func makeIncrementer() -> (() -> Int, () -> Int) {
    var runningTotal = 0
    
    func incrementer() -> Int {
        runningTotal += 1
        return runningTotal
    }
    
    func incrementer2() -> Int {
        runningTotal += 1
        return runningTotal
    }
    
    return (incrementer, incrementer2)
}

let x = makeIncrementer()

x.0() // 1
x.1() // 2

Clearly runningTotal is captured by reference by both incrementer and incrementer2. Is closure capturing the only case in which value types are treated as reference types?

Why wouldn’t Swift be implement so that runningTotal was Captured as a static copy at the time of capture so that each of the incrementer functions has their own “value”?

It seems like you could pretty easily run into a retain cycle with a struct even though it is a value type!

Consider:

struct MyValueType {
    
    var x: () -> ()
    
    init() {
        self.x = {
            print(self)
        }
    }
    
}

One might imagine that the capture of a value type like MyValueType would make a static copy of self for the closure, but if I understand correctly I actually just get a retain cycle. But it’s even worse, because (as I understand it) whether I do or not is optimization dependent!

"As an optimization, Swift may instead capture and store a copy of a value if that value is not mutated by a closure, and if the value is not mutated after the closure is created.”

Now it turns out that as of SE-0035 I get an error for the above code. Namely,

“Closure cannot implicitly capture a mutating self parameter.”

Kind of a strange error message for two reasons. The first is that nothing appears to be doing any mutating or declaring an intention of mutating. The second is that it’s not clear at all (to me at least) how to go about remedying the issue.

If I capture self explicitly with something like [s = self], am I getting a copy of self or a reference to self? I would assume a copy of self, but that’s not super clear given the somewhat surprising behavior of capturing value types by reference.

I would think the following would be a valid solution. Is there a better one?

struct MyValueType {
    
    var x: (() -> ())!
    
    init() {
        self.x = nil
        self.x = { [s = self] in
            print(s)
        }
    }
    
}

Is there a way to use currying to be more explicit about the semantics of passing a value into a closure?

Any help or discussion would be much appreciated!

Tyler


(Tyler Cloutier) #2

Also if capture lists for structs do capture by value, how can I avoid the newly added error “Closure cannot implicitly capture a mutating self parameter” without changing the original reference semantics of MyValueType?

Also why can’t I specify weak self for value types in capture lists if a captured value type is really just a reference anyway? What’s the purpose of that?

···

On Jul 24, 2016, at 2:07 AM, Tyler Fleming Cloutier <cloutiertyler@aol.com> wrote:

The Swift Programming Language book states:

"Reference counting only applies to instances of classes. Structures and enumerations are value types, not reference types, and are not stored and passed by reference.”

However consider the following example.

func makeIncrementer() -> (() -> Int, () -> Int) {
    var runningTotal = 0
    
    func incrementer() -> Int {
        runningTotal += 1
        return runningTotal
    }
    
    func incrementer2() -> Int {
        runningTotal += 1
        return runningTotal
    }
    
    return (incrementer, incrementer2)
}

let x = makeIncrementer()

x.0() // 1
x.1() // 2

Clearly runningTotal is captured by reference by both incrementer and incrementer2. Is closure capturing the only case in which value types are treated as reference types?

Why wouldn’t Swift be implement so that runningTotal was Captured as a static copy at the time of capture so that each of the incrementer functions has their own “value”?

It seems like you could pretty easily run into a retain cycle with a struct even though it is a value type!

Consider:

struct MyValueType {
    
    var x: () -> ()
    
    init() {
        self.x = {
            print(self)
        }
    }
    
}

One might imagine that the capture of a value type like MyValueType would make a static copy of self for the closure, but if I understand correctly I actually just get a retain cycle. But it’s even worse, because (as I understand it) whether I do or not is optimization dependent!

"As an optimization, Swift may instead capture and store a copy of a value if that value is not mutated by a closure, and if the value is not mutated after the closure is created.”

Now it turns out that as of SE-0035 I get an error for the above code. Namely,

“Closure cannot implicitly capture a mutating self parameter.”

Kind of a strange error message for two reasons. The first is that nothing appears to be doing any mutating or declaring an intention of mutating. The second is that it’s not clear at all (to me at least) how to go about remedying the issue.

If I capture self explicitly with something like [s = self], am I getting a copy of self or a reference to self? I would assume a copy of self, but that’s not super clear given the somewhat surprising behavior of capturing value types by reference.

I would think the following would be a valid solution. Is there a better one?

struct MyValueType {
    
    var x: (() -> ())!
    
    init() {
        self.x = nil
        self.x = { [s = self] in
            print(s)
        }
    }
    
}

Is there a way to use currying to be more explicit about the semantics of passing a value into a closure?

Any help or discussion would be much appreciated!

Tyler


(Zhao Xin) #3

For the capture part, it is by strong reference as document says:

“By default, a closure expression captures constants and variables from its

surrounding scope with strong references to those values. You can use a
capture list to explicitly control how values are captured in a closure.”
from: Apple Inc. “The Swift Programming Language (Swift 3 beta)”。 iBooks.
https://itun.es/us/k5SW7.l

Zhaoxin

···

On Sun, Jul 24, 2016 at 5:07 PM, Tyler Fleming Cloutier via swift-users < swift-users@swift.org> wrote:

The Swift Programming Language book states:

"Reference counting only applies to instances of classes. Structures and
enumerations are value types, not reference types, and are not stored and
passed by reference.”

However consider the following example.

func makeIncrementer() -> (() -> Int, () -> Int) {
    var runningTotal = 0

    func incrementer() -> Int {
        runningTotal += 1
        return runningTotal
    }

    func incrementer2() -> Int {
        runningTotal += 1
        return runningTotal
    }

    return (incrementer, incrementer2)
}

let x = makeIncrementer()

x.0() // 1
x.1() // 2

Clearly runningTotal is captured by reference by both incrementer and
incrementer2. Is closure capturing the only case in which value types are
treated as reference types?

Why wouldn’t Swift be implement so that runningTotal was Captured as a
static copy at the time of capture so that each of the incrementer
functions has their own “value”?

It seems like you could pretty easily run into a retain cycle with a
struct even though it is a value type!

Consider:

struct MyValueType {

    var x: () -> ()

    init() {
        self.x = {
            print(self)
        }
    }

}

One might imagine that the capture of a value type like MyValueType would
make a static copy of self for the closure, but if I understand correctly I
actually just get a retain cycle. But it’s even worse, because (as I
understand it) whether I do or not is optimization dependent!

"As an optimization, Swift may instead capture and store a *copy* of a
value if that value is not mutated by a closure, and if the value is not
mutated after the closure is created.”

Now it turns out that as of SE-0035 I get an error for the above code.
Namely,

“Closure cannot implicitly capture a mutating self parameter.”

Kind of a strange error message for two reasons. The first is that nothing
appears to be doing any mutating or declaring an intention of mutating. The
second is that it’s not clear at all (to me at least) how to go about
remedying the issue.

If I capture self explicitly with something like [s = self], am I getting
a copy of self or a reference to self? I would assume a copy of self, but
that’s not super clear given the somewhat surprising behavior of capturing
value types by reference.

I would think the following would be a valid solution. Is there a better
one?

struct MyValueType {

    var x: (() -> ())!

    init() {
        self.x = nil
        self.x = { [s = self] in
            print(s)
        }
    }

}

Is there a way to use currying to be more explicit about the semantics of
passing a value into a closure?

Any help or discussion would be much appreciated!

Tyler

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Zhao Xin) #4

Below code works.

struct MyValueType {

    var x: () -> () {

        return { print(self) }

    }

    init() {

// self.x = {

// print(self)

// }

    }

}

let a = MyValueType()

a.x() // MyValueType()

Zhaoxin

···

On Sun, Jul 24, 2016 at 5:11 PM, Tyler Fleming Cloutier via swift-users < swift-users@swift.org> wrote:

Also if capture lists for structs do capture by value, how can I avoid the
newly added error “Closure cannot implicitly capture a mutating self
parameter” without changing the original reference semantics of MyValueType?

Also why can’t I specify weak self for value types in capture lists if a
captured value type is really just a reference anyway? What’s the purpose
of that?

On Jul 24, 2016, at 2:07 AM, Tyler Fleming Cloutier <cloutiertyler@aol.com> > wrote:

The Swift Programming Language book states:

"Reference counting only applies to instances of classes. Structures and
enumerations are value types, not reference types, and are not stored and
passed by reference.”

However consider the following example.

func makeIncrementer() -> (() -> Int, () -> Int) {
    var runningTotal = 0

    func incrementer() -> Int {
        runningTotal += 1
        return runningTotal
    }

    func incrementer2() -> Int {
        runningTotal += 1
        return runningTotal
    }

    return (incrementer, incrementer2)
}

let x = makeIncrementer()

x.0() // 1
x.1() // 2

Clearly runningTotal is captured by reference by both incrementer and
incrementer2. Is closure capturing the only case in which value types are
treated as reference types?

Why wouldn’t Swift be implement so that runningTotal was Captured as a
static copy at the time of capture so that each of the incrementer
functions has their own “value”?

It seems like you could pretty easily run into a retain cycle with a
struct even though it is a value type!

Consider:

struct MyValueType {

    var x: () -> ()

    init() {
        self.x = {
            print(self)
        }
    }

}

One might imagine that the capture of a value type like MyValueType would
make a static copy of self for the closure, but if I understand correctly I
actually just get a retain cycle. But it’s even worse, because (as I
understand it) whether I do or not is optimization dependent!

"As an optimization, Swift may instead capture and store a *copy* of a
value if that value is not mutated by a closure, and if the value is not
mutated after the closure is created.”

Now it turns out that as of SE-0035 I get an error for the above code.
Namely,

“Closure cannot implicitly capture a mutating self parameter.”

Kind of a strange error message for two reasons. The first is that nothing
appears to be doing any mutating or declaring an intention of mutating. The
second is that it’s not clear at all (to me at least) how to go about
remedying the issue.

If I capture self explicitly with something like [s = self], am I getting
a copy of self or a reference to self? I would assume a copy of self, but
that’s not super clear given the somewhat surprising behavior of capturing
value types by reference.

I would think the following would be a valid solution. Is there a better
one?

struct MyValueType {

    var x: (() -> ())!

    init() {
        self.x = nil
        self.x = { [s = self] in
            print(s)
        }
    }

}

Is there a way to use currying to be more explicit about the semantics of
passing a value into a closure?

Any help or discussion would be much appreciated!

Tyler

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Tyler Cloutier) #5

This seems to just raise more questions than it answers. :stuck_out_tongue:

Why would one be allowed but not the other? They should be equivalent.

···

On Jul 24, 2016, at 5:49 AM, Zhao Xin <owenzx@gmail.com> wrote:

Below code works.

struct MyValueType {
    
    var x: () -> () {
        return { print(self) }
    }
    
    init() {
// self.x = {
// print(self)
// }
    }
}

let a = MyValueType()
a.x() // MyValueType()

Zhaoxin

On Sun, Jul 24, 2016 at 5:11 PM, Tyler Fleming Cloutier via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Also if capture lists for structs do capture by value, how can I avoid the newly added error “Closure cannot implicitly capture a mutating self parameter” without changing the original reference semantics of MyValueType?

Also why can’t I specify weak self for value types in capture lists if a captured value type is really just a reference anyway? What’s the purpose of that?

On Jul 24, 2016, at 2:07 AM, Tyler Fleming Cloutier <cloutiertyler@aol.com <mailto:cloutiertyler@aol.com>> wrote:

The Swift Programming Language book states:

"Reference counting only applies to instances of classes. Structures and enumerations are value types, not reference types, and are not stored and passed by reference.”

However consider the following example.

func makeIncrementer() -> (() -> Int, () -> Int) {
    var runningTotal = 0
    
    func incrementer() -> Int {
        runningTotal += 1
        return runningTotal
    }
    
    func incrementer2() -> Int {
        runningTotal += 1
        return runningTotal
    }
    
    return (incrementer, incrementer2)
}

let x = makeIncrementer()

x.0() // 1
x.1() // 2

Clearly runningTotal is captured by reference by both incrementer and incrementer2. Is closure capturing the only case in which value types are treated as reference types?

Why wouldn’t Swift be implement so that runningTotal was Captured as a static copy at the time of capture so that each of the incrementer functions has their own “value”?

It seems like you could pretty easily run into a retain cycle with a struct even though it is a value type!

Consider:

struct MyValueType {
    
    var x: () -> ()
    
    init() {
        self.x = {
            print(self)
        }
    }
    
}

One might imagine that the capture of a value type like MyValueType would make a static copy of self for the closure, but if I understand correctly I actually just get a retain cycle. But it’s even worse, because (as I understand it) whether I do or not is optimization dependent!

"As an optimization, Swift may instead capture and store a copy of a value if that value is not mutated by a closure, and if the value is not mutated after the closure is created.”

Now it turns out that as of SE-0035 I get an error for the above code. Namely,

“Closure cannot implicitly capture a mutating self parameter.”

Kind of a strange error message for two reasons. The first is that nothing appears to be doing any mutating or declaring an intention of mutating. The second is that it’s not clear at all (to me at least) how to go about remedying the issue.

If I capture self explicitly with something like [s = self], am I getting a copy of self or a reference to self? I would assume a copy of self, but that’s not super clear given the somewhat surprising behavior of capturing value types by reference.

I would think the following would be a valid solution. Is there a better one?

struct MyValueType {
    
    var x: (() -> ())!
    
    init() {
        self.x = nil
        self.x = { [s = self] in
            print(s)
        }
    }
    
}

Is there a way to use currying to be more explicit about the semantics of passing a value into a closure?

Any help or discussion would be much appreciated!

Tyler

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users