> On Aug 6, 2017, at 11:15 AM, Karl Wagner <razie...@gmail.com> wrote:
> 
> 
>> On 4. Aug 2017, at 20:15, John McCall via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>>> 
>>> On Aug 4, 2017, at 1:19 PM, Félix Cloutier via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> 
>>> 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.
>> 
>> Right.  I think maybe the name people keeping using for this feature is 
>> misleading; a better name would be "inline arrays" or "directly-stored 
>> arrays".  Having a fixed size is a necessary condition for storing the array 
>> elements directly, but the people asking for this feature are really asking 
>> for the different representation, not just the ability to statically 
>> constrain the size of an array.
>> 
>> That representation difference comes with a lot of weaknesses and 
>> trade-offs, but it's also useful sometimes.
>> 
>> John.
>> 
> 
> Right, and the question I’ve been asking (indirectly) is: why is this only 
> useful for arrays? Doesn’t it really apply to any value-type which allocates 
> storage which it manages with COW semantics (e.g. Dictionary, Set, Data, your 
> own custom types…)? Really, we want to inform the compiler that the 
> dynamically-allocated memory is part of the value - and if it sees that the 
> storage is only allocated once, it should be allowed to allocate that storage 
> inline with the value, on the stack.

There are absolutely things we could do as part of the Array implementation to 
dynamically avoid heap allocations for temporary arrays.  However, it would be 
very difficult to take advantage of that for arrays stored in temporary structs 
or enums; worse, even if we could, it still wouldn't have the optimal 
representation that people want for mathematical types like vectors and 
matrices.

John.


> 
> As I understand it, the only problem with this is when a function takes such 
> a value as a parameter and assigns it to some escaping reference (an ivar, 
> global, or capturing it inside an escaping closure).
> 
> So why can’t such assignments simply check if the value has inline storage 
> and copy it to the heap if necessary? The compiler should be able to optimise 
> the function so the check (which is really cheap anyway) only needs to happen 
> once per function. Because the entire type has value semantics, we can 
> substitute the original value with the copy for the rest of the function 
> (preventing further copies down the line).
> 
> 
> // Module one
> 
> import ModuleTwo
> 
> func doSomething() {
> 
>     let values = (0..<5).map { _ in random() }    // allocated inline, since 
> the size can never change
>     ModuleTwo.setGlobalItems(values)              // passes a stack-allocated 
> array to the (opaque) function
> }
> 
> // Module two
> 
> var GlobalItems = [Int]()
> var MoreGlobalItems = [Int]()
> 
> func setGlobalItems(_ newItems: [Int]) {
> 
>     GlobalItems = newItems          // assignment to escaping reference: 
> checks for inline storage, copies to heap if needed
> 
>     // all references to ‘newItems’ from this point refer to the copy known 
> to be on the heap
> 
>     MoreGlobalItems = newItems  // we already have a known out-of-line copy 
> of the value; no checks or copying needed
> }
> 
> // To make it more explicit...
> 
> func setGlobalItems_explicit(_ newItems: [Int]) {
> 
>     let newItems_heap = newItems.backing.isAllocatedInline ? 
> newItems(withBacking: newItems.backing.clone()) : newItems
>     GlobalItems       = newItems_heap
>     MoreGlobalItems   = newItems_heap
> }
> 
> 
> This would require some special language support for values that allocate 
> memory which is managed as COW.
> 
> - Karl
> 

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to