Thanks for refusing to let your pitch die. Something should eventually be done here and it's good to get feedback. The only reason to bring this up in Swift 4 is if we decide to outlaw some code pattern that's already in use. If this ends up just an additive convenience request, than it can be a bug report for now and come back in Swift 5. There have been a couple +1's already but I don't know whether it's a serious problem or just an annoyance.
Side note: don’t worry, simply declaring everything ‘var’ and passing them ‘inout’ shouldn’t break exclusive memory access. If you pass ‘inout’ to a non-mutable pointer, it’s just considered a “read” access. I'll speculate a bit and make some suggestions... > On Apr 20, 2017, at 12:10 PM, Anders Kierulf via swift-evolution > <[email protected]> wrote: > > Summary: Currently, only mutable values can be passed to UnsafeRawPointer, > except for a special case for arrays. That special case should be > generalized, allowing any values to be passed to UnsafeRawPointer without > using &. > > The following code shows the inconsistency in passing values to > UnsafeRawPointer: > > var varArray = [Int](repeating: 0, count: 6) > var varTuple = (0, 0, 0, 0, 0, 0) > > let letArray = [Int](repeating: 0, count: 6) > let letTuple = (0, 0, 0, 0, 0, 0) > > func get(_ pointer: UnsafeRawPointer, at index: Int) -> Int { > let a = pointer.bindMemory(to: Int.self, capacity: 6) > return a[index] > } > > // Array can be passed directly, automatically takes address. > _ = get(varArray, at: 2) // okay > _ = get(letArray, at: 2) // okay This works out because a special implicit conversion is doing the work for us. I think the special case is all about lightweight C interop with Swift Array. Let's not change this. > // When explicitly taking address, can only pass mutable variables. > _ = get(&varArray, at: 2) // okay, but seems inconsistent > _ = get(&letArray, at: 2) // fails: & not allowed I'll speculate that the type checker has a special case for `&varArray` for two reasons: 1. To prevent users from accidentally exposing the Array struct rather than its storage as a C pointer. That would be confusing to debug. 2. We need a mutable analog to the non-inout immutable case above, for lightweight C interop. We allow implicit UnsafeMutablePointer to UnsafePointer, so, I don't think there's anything inconsistent about `&varArray` here. I also think it's fine that we don't allow `&letArray`. Let's not change this. > // Passing tuple instead of array fails. > _ = get(varTuple, at: 2) // fails: wrong type > _ = get(letTuple, at: 2) // fails: wrong type Refusing to compile these cases would probably seem normal if we didn't support the first non-inout array case. I think we should allow both cases as a new, additive type system feature. > // Adding & to pass a tuple only works for mutable values. Having to > // pass the address using & means that any methods calling this must > // be mutating, even though they don't mutate. > _ = get(&varTuple, at: 2) // okay, but forces mutating > _ = get(&letTuple, at: 2) // fails: cannot pass immutable value Well, the `&varTuple` case only works by accident for raw pointers, but typed pointers will have the wrong type! See [SR-3590] Implicitly convert &Tuple to UnsafePointer<Tuple.Element>. The only reason I haven't pushed for this in Swift 4, along with several other important usability issues with UnsafePointer, is that (I thought) it's additive and I haven't wanted to compete for review bandwidth in this release cycle. However, come to think of it, this will break some very unlikely code: func foo(_ p: UnsafeMutablePointer<(Int, Int, Int)>) { p[0].0 = 42 } var a = (0, 1, 2) foo(&a) print(a) I think that's fair if migration is provided. > Passing a value to an UnsafeRawPointer parameter should not require use of &, > as that forces all code calling it to be mutating. Having a special case for > array also doesn't make sense, as the idea of UnsafeRawPointer is that we're > interpreting that memory content as whatever we want. Logged as SR-4649. Splitting hairs: the array case is really a special case and it does make sense. I'm *also* proposing a similar special case for homogeneous tuples. > Proposal: > - Never require & when passing value to UnsafeRawPointer. > - Always require & when passing value to UnsafeMutableRawPointer. +1 to your basic proposal. But I think each type system change needs to be more clearly spelled out. Probably with a separate bug for each. - Support non-inout homogeneous tuple argument conversion to UnsafePointer<Element>. (additive) - Support non-homgenous non-inout tuple argument conversion to UnsafeRawPointer. (additive) - Support inout homogeneous tuple argument conversion to UnsafeMutablePointer<Element>. See [SR-3590] Implicitly convert &Tuple to UnsafePointer<Tuple.Element>. (source breaking in ridiculous cases) - [SR-1956] `withUnsafePointer` shouldn't take its argument as `inout` (additive... we don't need to ban the inout syntax) The problem I have with [SR-4649] "Don't require & to pass value to UnsafeRawPointer", is that it seeks to create inconsistency between raw and non-raw pointers. That might make sense for non-homogenous tupes, but otherwise I don't think it's desirable. > > (Fixed size arrays are still needed, but with this tweak, workarounds can be > made to work.) Yes, they very much are needed to get people out of unsafe territory. -Andy _______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
