[swift-evolution] [Planning][Request] "constexpr" for Swift 5

Félix Cloutier felixcloutier at icloud.com
Fri Aug 4 14:16:46 CDT 2017

> Le 4 août 2017 à 11:39, Robert Bennett <rltbennett at icloud.com> a écrit :
>> That's not a concern with the `let` case that Robert brought up, since you can't mutate a `let` array at all.
>> The big thing is that unconstrained escape analysis is uncomputable. Since Swift array storage is COW, any function that receives the array as a parameter is allowed to take a reference on its storage. If the storage lives on the stack and that reference outlives the stack frame, you've got a problem. It's the same problem that motivated @escaping for closures.
>> You could allow storage to be on the stack by forcing user to make a pessimistic copy, which is possibly not an improvement.
> Good point. If this is only problematic when multiple threads are accessing an array, then it could still be worthwhile if all accesses are (provably) on the thread that created the array.

To be clear, it's a problem independently of multi-threading. `func foo() -> [Int] { return [1, 2, 3] }` is the most basic representation of it: you can't store the array in the stack frame if you return it. (To be fair, that one would be caught by escape analysis of any quality.) `func foo() { bar([1, 2, 3, 4]) }` is another example: if you don't know what `bar` does with the array, you can't store it on the stack because it might pass it to an object that lives on the heap and outlives `foo`, for instance. @escaping solves that problem for closures by specifically annotating parameters when the assigned closure could still be referenced after the called function returns.

> And pessimistic copying might still be worth it for arrays below a certain size — for instance, copying an Array<Int> of length 1 (and recall that the array in question is a constant so its size is known at compile time) would definitely be worth not having that array in heap memory.

You only need pessimistic copies when that copy escapes, and since it escapes, it needs to live on the heap by definition. Right now an array of size 1 passed to 4 objects on the heap has one single backing representation. With pessimistic copies, you'd get 4 times that buffer of size 1, which is definitely not an improvement.

> Going back to the literal notion of FSAs — fixed size arrays not necessarily on the stack — I think that simply copying Array’s implementation sans RangeReplaceableCollection conformance is not a bad way to go. Any optimizations used for `let` Arrays could probably be applied to this type of FSA.

We're actually splitting this in multiple directions. John talks of variable-sized arrays necessarily on the stack. :)

I see two useful characteristics to fixed-size arrays, which, uncoincidentally, are what it takes to use them for C interop:

Their storage is inlined into their container (whether it be the stack or an object)
Their length is part of their type (and not directly included with the data itself)

This is also enough to implement fixed-size arrays not necessarily on the stack, mind you.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170804/4884016d/attachment.html>

More information about the swift-evolution mailing list