[swift-evolution] [Pitch] Add the DefaultConstructible protocol to the standard library

Tony Allevato tony.allevato at gmail.com
Mon Dec 26 15:39:06 CST 2016

On Mon, Dec 26, 2016 at 1:19 PM David Sweeris <davesweeris at mac.com> wrote:

> On Dec 26, 2016, at 12:10, Tony Allevato <tony.allevato at gmail.com> wrote:
> On Mon, Dec 26, 2016 at 11:57 AM David Sweeris via swift-evolution <
> swift-evolution at swift.org> wrote:
> On Dec 26, 2016, at 11:35, Tony Allevato <allevato at google.com> 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

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).

> - Dave Sweeris
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161226/475d85d3/attachment.html>

More information about the swift-evolution mailing list