this builds on thoughts i posted over in SE-0527: RigidArray and UniqueArray - #21 by taylorswift , but it’s enough of a tangent that i figured it merits its own thread.
i’ve been delving into the “inline weakrefs” (UniqueArray<T?>) pattern that i talked about in the other thread, and i’m finding that UniqueArray is leading me towards writing force unwraps, which feels really indicative of a language or API flaw.
namely, if you’ve got an underlying buffer of UniqueArray<T?>, and you’re trying to expose that as an abstraction of non-optional T, the pieces just really don’t click together at all.
struct Arena<Object>: ~Copyable where Object: ~Copyable {
var weak: UniqueArray<Object?>
}
extension Arena where Object: ~Copyable {
subscript(unowned index: Int) -> Object {
_read {
switch self.weak[index] {
case let value?:
yield value
case nil:
fatalError("bad access, object (index = \(index)) is nil")
}
}
_modify {
if var object: Object = self.weak[index].take() {
// ^~~~~~
// Missing reinitialization of closure capture 'object' after consume
defer {
self.weak[index] = consume object
}
yield &object
} else {
fatalError("bad access, object (index = \(index)) is nil")
}
}
}
}
the only way that this accessor compiles if if i upcast back to T? and then force-unwrap that T? with !.
_modify {
if let object: Object = self.weak[index].take() {
var object: Object? = consume object
defer { self.weak[index] = object.take() }
yield &object!
} else {
fatalError("bad access, object (index = \(index)) is nil")
}
}
although it is unreachable in this sketch, i don’t think that “just write yield &object!” is advice that we want to be putting out there. i feel like defer, or at least the highest defer in a particular scope, ought to be able to consume local variables without reinitializing them.