> On Dec 26, 2016, at 1:39 PM, Tony Allevato <[email protected]> wrote:
> 
> 
> 
> On Mon, Dec 26, 2016 at 1:19 PM David Sweeris <[email protected] 
> <mailto:[email protected]>> wrote:
> 
> On Dec 26, 2016, at 12:10, Tony Allevato <[email protected] 
> <mailto:[email protected]>> wrote:
> 
>> On Mon, Dec 26, 2016 at 11:57 AM David Sweeris via swift-evolution 
>> <[email protected] <mailto:[email protected]>> wrote:
>> 
>> On Dec 26, 2016, at 11:35, Tony Allevato <[email protected] 
>> <mailto:[email protected]>> wrote:
>> 
>>> Mathematically, identities are associated with (type, operation) pairs, not 
>>> types alone.
>>> 
>>> This conversation has put me in the column of "numeric types shouldn't have 
>>> default initializers at all", personally.
>> 
>> I'd agree, except sometimes you need a T, any T, for when you want to create 
>> a "pre-sized" array for stuffing results into by index:
>> for i in ... {
>>     a[i] = ...
>> }
>> Simply saying "var a =[T](); a.reserveCapacity()" doesn't cut it because 
>> it'll still crash if you try to store anything in a[i] without somehow 
>> putting at least i+1 elements in the array first.
>> 
>> Array already has init(repeating:count:) that puts the responsibility of 
>> choosing the default value at the call site. If someone were writing a 
>> generic algorithm around this, then why not just propagate that 
>> responsibility out to its call site as well? That way, the algorithm isn't 
>> making any assumptions about what the "default" value is or even if one 
>> exists, and it doesn't impose additional requirements on the element type. 
>> For example, the user could get the default from a static factory method, an 
>> instance method on another object, or something else entirely.
> 
> Yeah, that's what I would use… The "filled out" example would be:
> extension Array {
>     public func pmap<T: DefaultInitable> (transform: (Element) -> T) -> [T] {
>         var result = Array<T>(repeating: T(), count: self.count) //Pick a 
> T... any T...
>         for i in self.indices {
>             result[i] = whateverTheConcurrentExectutionSyntaxIs(self[i], 
> transform)
>         }
>         return result
>     }
> }
> var thisCouldTakeAWhile = Array((0...10000)).pmap {
>     someReallySlowFunction($0)
> }
> At least I think that’d work... I haven’t tried it yet... Anyway, without 
> some way (any way) of getting an instance of T to fill in the `result` array, 
> it becomes much trickier to keep track of all the concurrently-calculated 
> transformed values. In this case, the semantics of `T()` are fairly 
> irrelevant because the semantics of the overall statement is just to work 
> around a language limitation (Swift not having separate allocation and 
> initialization phases), which doesn’t have anything to do with the semantics 
> of the initial value that got passed as the `repeating` argument.
> 
> This looks like it's abusing T() to stand in for nil, though. Before the 
> result[i] assignment executes, result[i] shouldn't conceptually have a 
> value—you're putting a default in there because the implementation requires 
> it. T() as a placeholder is just as valid/invalid as any other value in T's 
> space.
Pretty much, yeah.

> It's a square-peg-in-a-round-hole problem—design-wise, an array of optionals 
> would be a better fit, but you rightly don't want to return that from the 
> function, and you don't want to bear the cost of converting the array of 
> optionals to an array of non-optionals after the computation is complete. 
> That makes complete sense, but perhaps *that* is the problem that should be 
> addressed, instead of trying to use T() to avoid it? Or alternatively, a 
> parallel map operation should return an array of futures (or a collection 
> type that itself is a future).

Possibly correct… I think of it more as “solving the ’semantics’ problem from 
an unexpected direction”, which may well turn out to be an equivalent statement 
to yours (I don’t think I know enough about the topic to say for sure one way 
or the other). I believe adding those features is out-of-scope for now, though, 
so I was trying to illustrate a use-case that we might run into in the current 
language. Regarding using a `[T?]` and changing the last line to `return 
result.map {$0!}`, yeah, that’d absolutely work… it’s one more pass through the 
array than is computationally necessary, though, and some people need all the 
performance they can get. Someone mentioned `ManagedBuffer`… I’d forgotten that 
entire group of “*Buffer" types existed... While we’re waiting for certain 
features to come in-scope, it certainly sounds like one of them might be a 
better choice for this example.

- Dave Sweeris
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to