On the other hand, stored properties have do have this quality out of the box, and are implicitly borrow-only:
struct A: ~Copyable { }
struct B: ~Copyable {
let stored = A()
var computed: A { A() }
}
func hello(b: borrowing B) {
let y = b.stored // disallowed: 'b' is borrowed and cannot be consumed
let z = b.computed // allowed
}
Am I missing something? or is my only option basically:
i don't have much 'real world' experience with noncopyable types, so i may be off here, but i think if you can tolerate the use of underscored (yet longstanding) stdlib APIs, or experimental features, then this can perhaps be achieved by use of the _read/read coroutine accessor.
e.g. if i modify your code as so:
struct B: ~Copyable {
let stored = A()
var computed: A {
_read { yield A() }
}
}
then i get the error:
13 | func hello(b: borrowing B) {
14 | let y = b.stored // disallowed: 'b' is borrowed and cannot be consumed
15 | let z = b.computed // allowed
| |- error: 'b.computed' is borrowed and cannot be consumed
| `- note: consumed here
16 | }
17 |
Wow I didn't know this existed (I guess that's why they're underscored lol). I'd like to avoid experimental/non-standard features for now, given that I'm working on code that will be in a public library... but it's good to know that technically this is an option.
Here's a fun workaround I just found. Non-copyable values returned from subscripts and properties defined in a protocol are automatically treated as borrow-only, so a protocol (though introducing some indirection) gives an alternative, until the tools are available for explicitly specifying a value's ownership:
struct NonCopyableValue: ~Copyable { }
protocol ContainerProtocol: ~Copyable {
var noncopyable: NonCopyableValue { get }
subscript(_ i: Int) -> NonCopyableValue { get }
func getNoncopyable() -> NonCopyableValue
}
struct Container: ContainerProtocol, ~Copyable {
func getNoncopyable() -> NonCopyableValue {
fatalError()
}
subscript(i: Int) -> NonCopyableValue {
fatalError()
}
var noncopyable: NonCopyableValue {
fatalError()
}
}
func doSomething(with container: borrowing some ContainerProtocol & ~Copyable) {
let x = container.getNoncopyable() // allowed
let y = container[0] // disallowed
let z = container.noncopyable // disallowed
}
doSomething(with: Container())