despite ample enthusiasm, i have struggled to apply ~Copyable in any productive manner. perhaps i have simply not learned the correct patterns yet.
here’s a noncopyable struct of atomic counters:
import Atomics
struct Counters:~Copyable
{
let foosBarred:UnsafeAtomic<Int>
let barsFooed:UnsafeAtomic<Int>
// many many more atomics
init()
{
self.foosBarred = .create(0)
self.barsFooed = .create(0)
...
}
deinit
{
self.foosBarred.destroy()
self.barsFooed.destroy()
...
}
}
it is owned by an actor:
final
actor ServerLoop
{
private nonisolated
let plugins:Plugins
private nonisolated
let count:Counters
private
var state:State
}
now i need the actor to be able to yield its stored properties as something that is not isolated to the actor:
struct Server:~Copyable
{
let plugins:Plugins
let count:Counters
let state:Server.State
}
extension ServerLoop
{
func withServer(_ body:(borrowing Server) async throws -> Void) async rethrows
{
let server:Server = ???
}
}
although the Server could never escape or outlive the ServerLoop, there does not seem to be a way to temporarily pass the Counters to the closure argument without making Counters a class and falling back to reference counting.
indeed, giving up and going back to ARC pretty much describes my experience with ~Copyable. how can i get ~Copyable to do something useful here?
1 Like
This is a common pattern. I imagine handling it with two features that haven't been formally proposed yet: non-escapable types and borrowed references:
struct Server: ~Escapable
{
let plugins:Plugins
borrow count: Counters // borrowed reference
let state:Server.State
}
Maybe there's a clever way to reformulate the problem for use in 5.9. 
1 Like
i found one really hacky way to get this working:
struct Server:~Copyable
{
private
let loop:ServerLoop
let state:Server.State
}
extension Server
{
var count:Counters
{
_read { yield self.loop.count }
}
}
the compiler admits it doesn’t know how to compile this.
copy of noncopyable typed value. This is a compiler bug. Please file a bug with a small example of the bug
but i managed to trick it into compiling it anyway using immediately-executed closures.
let n:Int =
{
(count:borrowing Counters) in
count.foosBarred.load(ordering: .relaxed)
} (server.count)
who knows what demons i may have unleashed by doing this…
perhaps ~Copyable is not ready for prime time.
1 Like