Thanks for your answer! > I think the thing to do is to make two calls:
Eeeek, that's exactly what I wanted to avoid (which I actually think is the worst possible solution). > The inout-to-pointer is only available to function argument expressions; it's not even considered in a ternary expression here. Yes, I realized that (in fact I think the diagnostic makes this quite clear). I understand *why* it does not currently work, I'm merely suggesting that I think it *should* work. (It might be too hard to implement, just my opinion.) > In general, we can't support fully first-class pointers into managed Swift entities like Array and properties, without breaking the encapsulation of those abstractions. Yes, that's kind of obvious – what I am actually trying to suggest is that unsafe is already unsafe, so it might be OK to "break the encapsulation", for example by returning a pointer to the internal buffer without introducing a temporary. However, if you agree about sharply distinguishing Swift inout and unsafe + C address of (possibly in a way that my examples would work with the new unsafe address-of operator), I'm happy to narrow down my proposal to that specific case. On Thu, Dec 24, 2015 at 9:43 PM, Árpád Goretity <[email protected]> wrote: > Thanks for your answer! > > > I think the thing to do is to make two calls: > > Eeeek, that's exactly which I wanted to avoid (and which I think is the > worst possible solution). > > On Thu, Dec 24, 2015 at 5:26 PM, Joe Groff <[email protected]> wrote: > >> >> On Dec 23, 2015, at 5:35 PM, Árpád Goretity via swift-evolution < >> [email protected]> wrote: >> >> Hi everyone, >> >> I was recently trying to use a C API (LLVM for the record) that required >> passing an array to a function in the form of a pointer and a size. I >> couldn't find a straightforward way to pass a null pointer to the function >> in question conditionally (when the array is empty), since the following – >> simplified – code doesn't currently typecheck: >> >> // C function with signature: void foo(T *ptr, unsigned size) >> // imported into Swift as: (UnsafeMutablePointer<T>, UInt32) -> () >> var arr: [T] = [] >> foo(arr.count > 0 ? &arr[0] : nil, UInt32(arr.count)) >> >> The error is: result values in '? :' expression have mismatching types >> 'inout T' and '_' >> >> >> The diagnostic here sucks. The inout-to-pointer is only available to >> function argument expressions; it's not even considered in a ternary >> expression here, so the type checker can't find any way to match 'nil' and >> an inout. >> >> Since the inout operator (&) can only be used in function call arguments >> (so it's not exactly C's address-of), I believe that there's no easy way of >> elegantly passing a null pointer when the array is empty. (Yes, I could >> write two almost-identical calls, but meh…) And even if there is one (and >> I'm just missing it), the fact that the above code does not work seems >> inconsistent to me. >> >> I also realized that this specific issue generalizes to the (in)ability >> of passing one-past-end pointers – which would be equally valid and even >> more convenient in the above case, as the callee does not dereference the >> passed pointer when the count is 0, but in general, it can be applied to >> functions accepting [begin, end + 1) ranges. >> >> The problem here is that a one-past-end pointer does not reside at a >> valid index (pretty much by definition), so bounds checking kicks in and >> kills the program. >> >> >> Past-the-end indices are valid pointers (and valid in Swift collections >> in general). That's not the problem. `&arr[0]` fails because it's providing >> a temporary buffer connected only to the *element* &arr[0], rather than a >> buffer representing the entire array. This won't do what you expect for any >> Swift array, even if it's non-empty. >> >> In general, we can't support fully first-class pointers into managed >> Swift entities like Array and properties, without breaking the >> encapsulation of those abstractions. We can provide scoped operations like >> `withUnsafePointer` that give you a pointer to a possibly-temporary buffer >> that represents the value of that array or value for the duration of a >> block. When you say `CFunctionThatTakesPointer(&a)`, Swift's really >> wrapping that call in the equivalent of `withUnsafeMutableBufferPointer` on >> your behalf. You can see how that would be problematic if the wrapping >> needs to be conditional, such as if it appeared in a ternary or &&/|| >> expression. I think the thing to do is to make two calls: >> >> if arr.empty { >> foo(nil, 0) >> } else { >> foo(&arr, arr.count) >> } >> >> since preparing the buffer for the pointer itself isn't necessarily free, >> and you'd want to avoid that work if you don't need it. >> >> It might be OK to have the pointer produced for an empty array be null to >> begin with, which would avoid the need for this conditional at all. In most >> cases, you can't safely dereference a pointer to nothing anyway. I'm also >> sympathetic to the idea of disconnecting "address-of" and "inout", since it >> often leads to confusion like this. >> >> -Joe >> >> My proposed solutions: >> >> – Extend type inference for unsafe pointers and nil, so that when a >> value is passed by address to a function, it's not only the result of an >> &-expression that has its type inferred to be (or implicitly converted to) >> Unsafe[Mutable]Pointer, but if there's a nil somewhere around, such as the >> one in the example above, it gets promoted to that type too, just like NULL >> in C or nullptr in C++. >> >> – Stop overloading the inout '&' operator and using it for C-style >> address-of operations. I could imagine a similar, but distinct operator or >> even a library function (something along the lines of unsafeAddressOf) that >> specifically yields the physical address of its operand as an unsafe C >> pointer, and which is thus first-class in the sense that it may be used >> anywhere other expressions may be, not just as immediate call arguments. >> >> – Make array bounds checking more lenient when passing pointers to array >> elements into C functions. Bounds checking should, in these cases, allow >> indexing the one-past-end element of an array if (and only if) it is the >> argument of the address-of operator. >> >> Comments and questions are welcome (you might need clarification, as it's >> 2:35 AM here when I'm writing this…) >> >> Cheers, >> >> -- >> Author of the Sparkling language >> http://h2co3.org/ >> >> _______________________________________________ >> swift-evolution mailing list >> [email protected] >> https://lists.swift.org/mailman/listinfo/swift-evolution >> >> >> > > > -- > Author of the Sparkling language > http://h2co3.org/ > > -- Author of the Sparkling language http://h2co3.org/
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
