> On Dec 1, 2016, at 3:29 AM, Patrick Pijnappel via swift-dev > <swift-dev@swift.org> wrote: > > I'm implementing a COW big int type but am running into problems with > non-mutating functions (e.g. the + operator). Simplified example code below > shows AFAIK the default way to implement COW, but the non-mutating method > doesn't identify the reference as unique (even with -O), resulting in a > needless copy. > > I've tried everything I could think of, but only inout parameters seem to > work. How does the standard library do this, for e.g. String + String?
> > struct Foo { > var storage = Storage() > > class Storage { var x = 0 } > > init(_ x: Int) { storage.x = x } > > mutating func negate() { > if !isKnownUniquelyReferenced(&storage) { > print("Copy") > } > storage.x = -storage.x > } > > func negated() -> Foo { > var result = self // This counts as a second reference > result.negate() > return result > } > } > > func test() { > var a = Foo(5) > a.negate() > print(a.storage.x) > > let b = Foo(5) > let c = b.negated() > print(c.storage.x) > } > > test() Unfortunately, the compiler currently always passes the 'self' parameter of a nonmutating method with a caller-release convention, meaning that any local mutable copy necessarily needs to retain a local copy and can't consume the incoming 'self' value, and there's currently no way to override this. Theoretically, defining `negated` as a free function should enable this optimization, since non-'self' parameters are passed callee-release and can be consumed: func negate(foo: Foo) -> Foo { var result = foo result.negate() return result } though from what I've seen, the ARC optimizer doesn't always successfully shorten the lifetime of parameters enough to turn the "result = foo" into a move, which is a known bug. -Joe _______________________________________________ swift-dev mailing list swift-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-dev