Joe_Groff
(Joe Groff)
1
The global withUnsafePointer and withUnsafeBytes functions currently require their pointee argument to be inout. Because these functions restrict what you're allowed to do with the pointer your closure receives—specifically, you can't use the pointer after the closure returns, and you can't mutate through it—there's no formal reason they couldn't also work on immutable arguments with those same restrictions. In effect, the immutable-argument versions can be written in terms of the inout-argument ones:
func withUnsafeBytes<T, Result>(of value: T, _ body: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result {
var value2 = value
return withUnsafeBytes(of: &value2, body)
}
like many people do manually today, though the copy shouldn't really be necessary, particularly now with the default +0 argument convention. Here's a PR that implements variants of these functions for immutable values: stdlib: Add withUnsafeBytes(of:) and withUnsafePointer(to:) for immutable arguments. by jckarter · Pull Request #15608 · apple/swift · GitHub Does anyone see any problems with proposing adding these forms?
7 Likes
jrose
(Jordan Rose)
2
Potential downside: previously, withUnsafeBytes(&self.storedProp) would give you the same buffer pointer each time and withUnsafeBytes(self.storedProp) would fail. With this change, the latter will now succeed but always do a load if the closure mentions self in any way.
I think the upside probably outweighs this downside, though.
Joe_Groff
(Joe Groff)
3
You're not formally guaranteed to get the same or different pointers in either situation. It's possible in theory with the +0 convention for the immutable forms to produce the same pointer for stored properties in similar situations as we do with the inout forms.
jrose
(Jordan Rose)
4
That's true, the direct inout-to-pointer conversion (&self.foo for an argument with pointer type) is the only place where that's really guaranteed.
Joe_Groff
(Joe Groff)
5
It is true on the other hand that, without move-only types and/or a "no implicit copies" language mode, that the immutable argument value is more likely to introduce a temporary copy if the compiler can't guarantee the immutability of the value's storage, whereas &prop more forcefully asserts exclusive access to prop. We don't have to take the inout form away, though.
4 Likes
Joe_Groff
(Joe Groff)
6
1 Like
+1 from me, otherwise I have to make a copy of the value first. Making a copy of the value leads to reliance on an optimization to elide the copy that doesn't/might-not happen (SR-4581). I'd rather rely on language behavior than hope for optimizations.
1 Like
jrose
(Jordan Rose)
8
The language behavior says that there's a copy, and this proposal doesn't change that.
Joe_Groff
(Joe Groff)
9
The argument is at least passed at +0, allowing it to share representation with the caller-side argument. When we flesh out the borrow model we can more formally guarantee when copies can be avoided.
2 Likes