> On Dec 5, 2017, at 4:05 PM, Douglas Gregor via swift-dev 
> <swift-dev@swift.org> wrote:
> 
> 
> 
>> On Dec 5, 2017, at 3:56 PM, David Hart <da...@hartbit.com 
>> <mailto:da...@hartbit.com>> wrote:
>> 
>> But that wouldn’t allow surfacing a func type(named: String) Standard 
>> Library function that worked on any type, wouldn’t it (like the Dictionary 
>> with non-Hashable key)?
> 
> As I noted to John, we still need to handle the general case for the 
> right-hand side of a same-type constraint, which can be an arbitrary type. 
> That requires all of the functionality of type(named:). 
> 
> That said, from my perspective, adding type(named:) is entirely “gravy”. We 
> get it for free from this implementation plan, but IMO it could be added to 
> some later version of Swift and that would be fine.

I agree that surfacing it in the stdlib is gravy, but implementing the 
underlying mechanism is important, IMO. Field type vector accessors are a large 
contributor to binary code size (I wouldn’t be surprised if it was 5-10% for 
some projects) and implementing a more efficient encoding for ABI stability 
would be nice.

Slava

> 
>       - Doug
> 
>> 
>> On 6 Dec 2017, at 00:42, John McCall via swift-dev <swift-dev@swift.org 
>> <mailto:swift-dev@swift.org>> wrote:
>> 
>>>> On Dec 5, 2017, at 5:28 PM, Douglas Gregor via swift-dev 
>>>> <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:
>>>> Hi all,
>>>> 
>>>> The main missing piece for conditional conformances 
>>>> (https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md
>>>>  
>>>> <https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md>)
>>>>  is support for dynamic casting. Right now, dynamic casting that queries a 
>>>> conditional conformance will always fail. Here’s an example:
>>>> 
>>>> protocol P {
>>>>   func foo()
>>>> }
>>>> 
>>>> struct X : P {
>>>>   func foo() { print("X.P") }
>>>> }
>>>> 
>>>> struct Y<T> {
>>>>   var wrapped: T
>>>> }
>>>> 
>>>> extension Y: P where T: P {
>>>>   func foo() { wrapped.foo() }
>>>> }
>>>> 
>>>> func tryAsP(_ value: Any) {
>>>>   if let p = value as? P {
>>>>     p.foo()
>>>>   }
>>>> }
>>>> 
>>>> let yx = Y(wrapped: X())
>>>> tryAsP(yx)
>>>> 
>>>> This won’t print anything, but should print “X.P”. We’d like to fix that :)
>>>> 
>>>> Joe Groff, Slava, and I discussed an approach to implement dynamic casting 
>>>> for conditional conformances, which I’d like to outline here.
>>>> 
>>>> Background
>>>> The Swift runtime expresses the conformance of a specific type (say 
>>>> Array<Int>) to a particular protocol (say, Equatable) using a witness 
>>>> table. Witness tables contain the actual associated types as well as 
>>>> function pointers for each of the requirements of a protocol. Slava and 
>>>> John’s talk on Implementing Swift Generics 
>>>> (https://llvm.org/devmtg/2017-10/#talk15 
>>>> <https://llvm.org/devmtg/2017-10/#talk15>) gives a bunch of background 
>>>> here.
>>>> 
>>>> When a conformance is conditional, the witness table also stores the 
>>>> conditional requirements. So, the witness table for Array<Int>: Equatable 
>>>> has to store the witness table Int: Equatable. In the example above, the 
>>>> witness table for Y<X>: P needs to store a pointer to the witness table X: 
>>>> P. The compiler knows how to pass along the witness tables needed for a 
>>>> conditional conformance, but for runtime casting to work, we need to (1) 
>>>> evaluate all of the conditional requirements to determine whether they 
>>>> apply (e.g., does T: P for a specific T?) and then (2) pass those witness 
>>>> tables along when building the witness table. The cast should fail if any 
>>>> of the conditional requirements goes unsatisfied, and produce a valid 
>>>> witness table otherwise.
>>>> 
>>>> Protocol Conformance Records
>>>> Whenever code declares conformance of a particular type to a given 
>>>> protocol, the compiler emits a “protocol conformance record” (documented 
>>>> at 
>>>> https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst#protocol-conformance-records
>>>>  
>>>> <https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst#protocol-conformance-records>).
>>>>  These protocol conformance records state the type declaring conformance 
>>>> (e.g., Y) and the protocol (e.g., P), and then provide a witness table 
>>>> accessor to form the witness table given type metadata for a specific type 
>>>> instance (e.g., Y<X>). In the case of a conditional conformance, this 
>>>> accessor also needs to be passed the witness tables for any conditional 
>>>> requirements, e.g., the witness table for X: P. 
>>>> 
>>>> Conditional Requirements in Protocol Conformance Records
>>>> Somehow we need to dynamically evaluate the conditional requirements. For 
>>>> example, we need to know that for the X<T>: P conformance to be valid, we 
>>>> need T: P to hold for the given T. So, we’ll extend the protocol 
>>>> conformance record with an encoding of those requirements. Fortunately, we 
>>>> already have a way to encode arbitrary generic requirements: the mangling 
>>>> of a generic-signature (see 
>>>> https://github.com/apple/swift/blob/master/docs/ABI/Mangling.rst#generics 
>>>> <https://github.com/apple/swift/blob/master/docs/ABI/Mangling.rst#generics>)
>>>>  already encodes arbitrary generic requirements, so we can put a string 
>>>> comprised of the mangled conditional requirements into the protocol 
>>>> conformance record.
>>>> 
>>>> When evaluating a conditional conformance, we demangle the conditional 
>>>> requirements to get something like: “T must conform to P”. We then need to 
>>>> substitute the type arguments (e.g., X) for the  corresponding type 
>>>> parameters (T) to form type metadata for the requirements. In this case, 
>>>> we’d get the type metadata pointer for Y and the protocol descriptor for 
>>>> P, and then call swift_conformsToProtocol() to determine whether the 
>>>> requirement holds. If it does, swift_conformsToProtocol() produces the Y: 
>>>> P witness table we need to pass along to the witness table accessor.
>>>> 
>>>> Note that the conditional requirements can be arbitrarily complicated. For 
>>>> example, given:
>>>> 
>>>> extension Dictionary: P where Value == (Key) -> Bool { … }
>>>> 
>>>> Even though the result of evaluating this same-type requirement doesn’t 
>>>> need to be passed along to the witness table accessor, we still need to 
>>>> evaluate the requirement to determine whether the conditional conformance 
>>>> to P applies. To do so, we will need to substitute type arguments for both 
>>>> Value and Key, and need to form the type metadata representing the 
>>>> (substituted) function type (Key) -> Bool to determine if it is equivalent 
>>>> to the (substituted) type of Value (which is then determined by type 
>>>> metadata pointer equality because the runtime uniques type metadata). 
>>>> 
>>>> Looking up Type Metadata For a Mangled Name
>>>> To perform that mapping from a mangled type in a conditional requirement 
>>>> to type metadata, we effectively need an operation to take a mangled type 
>>>> name and turn it into a type metadata pointer. This is something we could 
>>>> surface in the Swift standard library/runtime as, e.g.,
>>>> 
>>>> func type(named: String) -> Any.Type?
>>>> 
>>>> to take a mangled type name and try to get the type metadata for it. From 
>>>> there, one can query protocol conformances that (say) allow one to 
>>>> construct instances of the arbitrarily-named type. Think of it as 
>>>> NSClassFromString for any type in the Swift language, including 
>>>> specializations of generic types.
>>>> 
>>>> To get here, we’ll also need to extend the nominal type descriptor 
>>>> (https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst#nominal-type-descriptor
>>>>  
>>>> <https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst#nominal-type-descriptor>)
>>>>  to contain the generic signature of a nominal type. That let’s us safely 
>>>> create specializations of generic types. For example, if one tries to form 
>>>> Dictionary<A, B> where A does not conform to Hashable, type(named:) should 
>>>> return “nil” rather than an invalid type. The same logic that will be used 
>>>> to form type metadata when checking conditional requirements will apply 
>>>> here. Indeed, it’s probably worth proposing type(named:) as a separate 
>>>> language feature on the path to conditional conformances.
>>>> 
>>>> Looking Forward: Generalized Existentials
>>>> Generalized existentials 
>>>> (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generalized-existentials
>>>>  
>>>> <https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generalized-existentials>)
>>>>  allows us to express more kinds of “existential” type in the language, 
>>>> e.g., “A Collection of some type of Element that we know is Equatable”, 
>>>> e.g.,
>>>> 
>>>> var a: Any<Collection where .Element: Equatable>
>>>> a = [1, 2, 3, 4, 5]
>>>> a = Set([“a”, “b”, “c”])
>>>> 
>>>> To get there, we can change (or extend) the protocol metadata 
>>>> (https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst#protocol-metadata
>>>>  
>>>> <https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst#protocol-metadata>)
>>>>  to contain a complete generic signature, which can be evaluated 
>>>> dynamically using the same mechanisms described above. For example:
>>>> 
>>>> func f(any: Any) {
>>>>   if let c = any as? Any<Collection where .Element: Equatable> { … }
>>>> }
>>>> 
>>>> We should make the metadata change to allow this form of generalized 
>>>> existentials before locking down the ABI, even if we don’t settle on the 
>>>> feature in the surface language.
>>>> 
>>>> Thoughts?
>>> 
>>> Couldn't we just encode a metadata path for the associated type and then do 
>>> the conformance lookup?
>>> 
>>> John.
>>> _______________________________________________
>>> swift-dev mailing list
>>> swift-dev@swift.org <mailto:swift-dev@swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-dev 
>>> <https://lists.swift.org/mailman/listinfo/swift-dev>
> 
> _______________________________________________
> swift-dev mailing list
> swift-dev@swift.org
> https://lists.swift.org/mailman/listinfo/swift-dev

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

Reply via email to