Let me first say that this new draft does a great job of explaining the current situation and the goals of the proposal. The revised “Motivation” section in particular is very clearly written and introduces the concepts effectively.
I found the previous versions to be highly confusing, and I did not understand from them what was being proposed and why. After reading this one, I feel that I finally comprehend the situation, both in terms of how metatypes behave today and how the authors would like them to work. This is still an area where I do not have much expertise, so I look forward to hearing what better-versed people think of the overall approach as well as the specific details. Nevin On Wed, Sep 28, 2016 at 6:18 AM, Adrian Zubarev via swift-evolution < swift-evolution@swift.org> wrote: > Formatted version: https://github.com/DevAndArtist/swift-evolution/ > blob/refactor_metatypes/proposals/0126-refactor-metatypes.md > ------------------------------ > Refactor Metatypes > > - Proposal: SE–0126 > <http://0126-refactor-metatypes-repurpose-t-dot-self-and-mirror.md> > - Authors: Adrian Zubarev <https://github.com/DevAndArtist>, Anton > Zhilin <https://github.com/Anton3>, Brent Royal-Gordon > <https://github.com/brentdax> > - Status: *Revision* > - Review manager: Chris Lattner <http://github.com/lattner> > - Revision: 2 > - Previous Revisions: 1 > > <https://github.com/apple/swift-evolution/blob/83707b0879c83dcde778f8163f5768212736fdc2/proposals/0126-refactor-metatypes-repurpose-t-dot-self-and-mirror.md> > > Introduction > > This proposal removes .Type and .Protocol in favor of two generic-style > syntaxes and aligns global type(of:) function (SE–0096) to match the > changes. > > Swift-evolution thread (post Swift 3): > > - [Pitch] Refactor Metatypes > > Older swift-evolution threads: [1] > <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160718/025115.html>, > [2] > <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160718/024772.html>, > [3] > <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160704/023818.html> > Motivation > > Every type T has an instance, accessible through T.self, which represents > the type itself. Like all instances in Swift, this “type instance” itself > has a type, which is referred to as its “metatype”. The metatype of T is > written T.Type. The instance members of the metatype are the same as the > static or class members of the type. > > Metatypes have subtype relationships which reflect the types they > represent. For instance, given these types: > > protocol Proto {} > class Base {} > class Derived: Base, Proto {} > > Derived.Type is a subtype of both Base.Type and Proto.Type (and Any.Type). > That means that Derived.self can be used anywhere a Derived.Type, > Base.Type, Proto.Type, or Any.Type is called for. > > Unfortunately, this simple picture is complicated by protocols. Proto.self > is actually of type Proto.Protocol, not type Proto.Type. This is > necessary because the protocol does not, and cannot, conform to itself; it > requires conforming types to provide static members, but it doesn’t > actually provide those members itself. Proto.Type still exists, but it is > the supertype of all types conforming to the protocol. > > Making this worse, a generic type always uses T.Type to refer to the type > of T.self. So when Proto is bound to a generic parameter P, P.Type is the > same as Proto.Protocol. > > This shifting of types is complicated and confusing; we seek to clean up > this area. > > We also believe that, in the long term, the dot syntax will prevent us > from implementing certain future enhancements that might be valuable: > > - Moving the implementation of metatypes at least partly into the > standard library. > - Adding members available on all type instances for features like > read-write reflection or memory layout information. > - Conforming metatypes to protocols like Hashable or > CustomStringConvertible. > - Offering straightforward syntaxes for dynamic features like looking > up types by name. > > Proposed solution > > We abolish .Type and .Protocol in favor of two generic-style syntaxes: > > - > > Type<T> is the concrete type of T.self. A Type<T> only ever has one > instance, T.self; even if T has a subtype U, Type<U> is not a subtype > of Type<T>. > - > > Subtype<T> is the supertype of all Types whose instances are subtypes > of T, including T itself: > - > > If T is a struct or enum, then Type<T> is the only subtype of > Subtype<T>. > - > > If T is a class, then Type<T> and the Types of all subclasses of T are > subtypes of Subtype<T>. > - > > If T is a protocol, then the Types of all concrete types conforming to > T are subtypes of Subtype<T>. Type<T> is not itself a subtype of > Subtype<T>, or of any Subtype other than Subtype<Any>. > - > > Structural types follow the subtype/supertype relationships of their > constituent types. For instance: > - > > Type<(NSString, NSString)> is a subtype of Subtype<(NSObject, > NSObject)> > - > > Metatypes of functions are a little bit more special (the subtyping > relation on functions flips around for parameter types > > <https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)> > ): > - Type<(Any) -> Void> is a subtype of Subtype<(Int) -> Void> etc. > - Type<(Void) -> Int> is a subtype of Subtype<(Void) -> Any> > > In this new notation, some of our existing standard library functions > would have signatures like: > > func unsafeBitCast<T, U>(_: T, to type: Type<U>) -> U > func ==(t0: Subtype<Any>?, t1: Subtype<Any>?) -> Bool > func type<T>(of: T) -> Subtype<T> // SE-0096 > > That last example, type(of:), is rather interesting, because it is > actually a magic syntax rather than a function. We propose to align this > syntax with Type and Subtype by renaming it to Subtype(of:). We believe > this is clearer about both the type and meaning of the operation. > > let anInstance: NSObject = NSString() > let aClass: Subtype<NSObject> = Subtype(of: anInstance) > > print(aClass) // => NSString > > More details: > > - > > Every static or class member of T which can be called on all subtypes > is an instance member of Subtype<T>. That includes: > - > > Static/class properties and methods > - > > Required initializers (as methods named init) > - > > Unbound instance methods > - > > The Type<T> of a concrete type T has all of the members required by > Subtype<T>, plus non-required initializers. > - > > The Type<T> of a protocol T includes only unbound instance methods of T > . > - > > If T conforms to P, then Subtype<T> is a subtype of Subtype<P>, even > if T is a protocol. > - > > The type of Subtype<T>.self is Type<Subtype<T>>. > - > > The type of Type<T>.self is Type<Type<T>>, which is not a subtype of > any type except Subtype<Type<T>>. There is an infinite regress of > Type<...<Type<T>>>s. > - > > Subtypes are abstract types similar to class-bound protocols; they, > too, support identity operations. > - > > Types are concrete reference types which have identities just like > objects do. > > swift Int.self === Int.self // true Int.self === Any.self // false > > *Visual metatype relationship example (not a valid Swift code)* > > protocol Foo { > static func foo() > func instanceMethodFoo() > } > > protocol Boo : Foo { > static func foo() > static func boo() > func instanceMethodFoo() > func instanceMethodBoo() > } > > class A : Foo { > static func foo() { ... } > func instanceMethodFoo() { ... } > } > > class B : A, Boo { > static func boo() { ... } > func instanceMethodBoo() { ... } > } > > /// Swift generates metatypes along the lines of: > /// > /// Syntax: `meta protocol Subtype<T>` - only metatypes can conform to these > meta protocols > /// Syntax: `final meta class Type<T>` - metatype > /// Note: `CapturedType` represents `Self` of `T` in `Subtype<T>` > > // For Any: > meta protocol Subtype<Any> : meta class { > var `self`: Self { get } > } > > final meta class Type<Any> : Subtype<Any> { > var `self`: Type<Any> { ... } > } > > // For Foo: > meta protocol Subtype<Foo> : Subtype<Any> { > var `self`: Self { get } > func foo() > func instanceMethodFoo(_ `self`: CapturedType) -> (Void) -> Void > } > > final meta class Type<Foo> : Subtype<Any> { > var `self`: Type<Foo> { ... } > func instanceMethodFoo(_ `self`: Foo) -> (Void) -> Void { ... } > } > > // For Boo: > meta protocol Subtype<Boo> : Subtype<Foo> { > var `self`: Self { get } > func boo() > func instanceMethodBoo(_ `self`: CapturedType) -> (Void) -> Void > } > > final meta class Type<Boo> : Subtype<Any> { > var `self`: Type<Boo> { ... } > func instanceMethodFoo(_ `self`: Boo) -> (Void) -> Void { ... } > func instanceMethodBoo(_ `self`: Boo) -> (Void) -> Void { ... } > } > > // For A: > meta protocol Subtype<A> : Subtype<Foo> { > var `self`: Self { get } > func foo() > func instanceMethodFoo(_ `self`: CapturedType) -> (Void) -> Void > } > > final meta class Type<A> : Subtype<A> { > var `self`: Type<A> { ... } > func foo() { ... } > func instanceMethodFoo(_ `self`: A) -> (Void) -> Void { ... } > } > > // For B: > meta protocol Subtype<B> : Subtype<A>, Subtype<Boo> { > var `self`: Self > func foo() > func boo() > func instanceMethodFoo(_ `self`: CapturedType) -> (Void) -> Void > func instanceMethodBoo(_ `self`: CapturedType) -> (Void) -> Void > } > > final meta class Type<B> : Subtype<B> { > var `self`: Type<B> { ... } > func foo() { ... } > func boo() { ... } > func instanceMethodFoo(_ `self`: B) -> (Void) -> Void { ... } > func instanceMethodBoo(_ `self`: B) -> (Void) -> Void { ... } > } > > *Some examples* > > // Types: > protocol Foo {} > protocol Boo : Foo {} > class A : Foo {} > class B : A, Boo {} > struct S: Foo {} > > // Metatypes: > let a1: Type<A> = A.self //=> Okay > let p1: Type<Foo> = Foo.self //=> Okay > let p2: Type<Boo> = C.self //=> Error -- `C` is not the same as `Foo` > > let any_1: Subtype<Any> = A.self //=> Okay > let any_2: Subtype<Any> = Foo.self //=> Okay > > let a_1: Subtype<A> = A.self //=> Okay > let p_1: Subtype<Foo> = A.self //=> Okay > let p_2: Subtype<Foo> = Foo.self //=> Error -- `Type<Foo>` is not a subtype > of `Subtype<Foo>` > > // Generic functions: > func dynamic<T>(subtype: Subtype<Any>, `is` _: Type<T>) -> Bool { > return type is Subtype<T> > } > > func dynamic<T>(subtype: Subtype<Any>, `as` _: Type<T>) -> Subtype<T>? { > return type as? Subtype<T> > } > > let s1: Type<S> = S.self > > dynamic(subtype: s1, is: Foo.self) //=> true > dynamic(subtype: s1, as: Foo.self) //=> an `Optional<Subtype<Foo>>` > > Future Directions > > - > > We could allow extensions on Type and perhaps on Subtype to add > members or conform them to protocols. This could allow us to remove some > standard library hacks, like the non-Equatable-related == operators > for types. > - > > It may be possible to implement parts of Type as a fairly ordinary > final class, moving code from the runtime into the standard library. > - > > We could offer a Subtype(ofType: Type<T>, named: String) > pseudo-initializer which would allow type-safe access to classes by name. > - > > We could offer other reflection and dynamic features on Type and > Subtype. > - > > We could move the MemoryLayout members into Type (presumably > prefixed), removing the rather artificial MemoryLayout enum. > - > > Along with other generics enhancements, there may be a use for a > Subprotocol<T> syntax for any protocol requiring conformance to > protocol T. > > Impact on existing code > > This is a source-breaking change that can be automated by a migrator. > > We suggest the following migration process; this can differ from the final > migration process implemented by the core team if this proposal will be > accepted: > > - Any.Type is migrated to Subtype<Any>. > - If T.Type is in function parameter, where T is a generic type > parameter, then it’s migrated to Type<T>. > - Every T.Protocol will be replaced with Type<T>. > - Every T.Type in a dynamic cast will be replaced with Subtype<T>. > - If static members are called on a metatype instance, then this > instance is migrated to Subtype<T>. > - Return types of functions are migrated to Subtype<T>. > - Variable declarations is migrated to Subtype<T>. > > Alternatives considered > > Other names for Type and Subtype were considered: > > - Type: SpecificType, Metatype or ExactType. > - Subtype: Supertype, Base, BaseType, ExistentialType or TypeProtocol. > > Alternatively the pseudo initializer Subtype(of:) could remain as a > global function: > > public func subtype<T>(of instance: T) -> Subtype<T> > > > > -- > Adrian Zubarev > Sent with Airmail > > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution > >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution