> On Dec 1, 2017, at 11:42 AM, Nevin Brackett-Rozinsky 
> <[email protected]> wrote:
> 
> On Thu, Nov 30, 2017 at 7:28 PM, Douglas Gregor via swift-evolution 
> <[email protected] <mailto:[email protected]>> wrote:
> A Rough Proposal
> I’ve been thinking about this for a bit, and I think there are three ways in 
> which we should be able to infer an associated type witness:
> 
> Associated type defaults, which are specified with the associated type 
> itself, e.g.,
> 
>   associatedtype Indices = DefaultIndices<Self>
> 
> These are easy to reason about for both the programmer and the compiler.
> Typealiases in (possibly constrained) protocol extensions, e.g.,
> 
>   extension RandomAccessCollection where Index : Strideable, Index.Stride == 
> IndexDistance {
>     typealias RandomAccessCollection.Indices = CountableRange<Index>
>   }
> 
> I’m intentionally using some odd ‘.’ syntax here to indicate that this 
> typealias is intended only to be found when trying to satisfy an associated 
> type requirement, and is not a general typealias that could be found by 
> normal name lookup. Let’s set the syntax bike shed aside for the moment. The 
> primary advantage of this approach (vs. inferring Indices from “var Indices: 
> CountableRange<Index>” in a constrained protocol extension) is that there’s a 
> real typealias declaration that compiler and programmer alike can look at and 
> reason about based just on the name “Indices”. 
> 
> Note that this mechanism technically obviates the need for (1), in the same 
> sense that default implementations in protocols 
> <https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#default-implementations-in-protocols->
>  are merely syntactic sugar.
> Declarations within the nominal type declaration or extension that declares 
> conformance to the protocol in question. This is generally the same approach 
> as described in “associated type inference” above, where we match 
> requirements of the protocol against declarations that could satisfy those 
> requirements and infer associated types from there. However, I want to turn 
> it around: instead of starting with the requirements of the protocol any 
> looking basically anywhere in the type or any protocol to which it conforms 
> (for implementations in protocol extensions), start with the declarations 
> that the user explicitly wrote at the point of the conformance and look for 
> requirements they might satisfy. For example, consider our initial example:
> 
>   extension MyCollection: RandomAccessCollection {    
>     var startIndex: Int { return contents.startIndex }
>     var endIndex: Int { return contents.endIndex }
>     subscript(index: Int) -> T { return contents[index] }
>   }
> 
> Since startIndex, endIndex, and subscript(_:) are declared in the same 
> extension that declares conformance to RandomAccessIterator, we should look 
> for requirements with the same name as these properties and subscript within 
> RandomAccessCollection (or any protocol it inherits) and infer Index := Int 
> and Element := T by matching the type signatures. This is still the most 
> magical inference rule, because there is no declaration named “Index” or 
> “Element” to look at. However, it is much narrower in scope than the current 
> implementation, because it’s only going to reason from the (probably small) 
> set of declarations that the user wrote alongside the conformance, so it’s 
> more likely to be intentional. Note that this is again nudging programmers 
> toward the style of programming where one puts one protocol conformance per 
> extension, which is admittedly my personal preference.
> 
> Thoughts?
> I think this approach is more predictable and more implementable than the 
> current model. I’m curious whether the above makes sense to someone other 
> than me, and whether it covers existing use cases well enough. Thoughts?
> 
>       - Doug
> 
> 
> How does this work with retroactive conformance, especially where all the 
> protocol requirements already exist on a type and an empty extension declares 
> conformance? For example, suppose Module A declares a protocol with 
> associated types, and Module B has a struct which naturally possesses all the 
> required members to conform (maybe B handles Double concretely, while A can 
> work with any FloatingPoint, or some such). As a client importing both 
> modules and providing an empty extension to conform B’s struct to A’s 
> protocol, will the associated types be inferred?

No, the associated types will not be inferred in this case. That will be a 
change in behavior (and a source compatibility regression).

> Also, have you considered the possibility of allowing protocol authors to 
> specify which types should be inferred from which requirements? For example 
> Collection might demarcate “startIndex” as the source-of-truth for inferring 
> “Index”, and “subscript (Index)->Element” as the source-of-truth for 
> inferring “Element”.

This did come up a while ago, but it always felt like a hack… why infer from 
startIndex/endIndex rather than from “indices”, given that one set can be 
implemented in terms of the other with sufficiently-good inference? Why should 
the protocol author have to make sure a decision?

        - Doug


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

Reply via email to