First off, I agree with Nevin (up-thread) that this is a much clearer version of the previous proposal, well done.
> On 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 > > <https://github.com/DevAndArtist/swift-evolution/blob/refactor_metatypes/proposals/0126-refactor-metatypes.md> > Refactor Metatypes > > Proposal: SE–0126 > <x-msg://5/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 > <applewebdata://A0AAC176-7F99-483F-BC96-BDA55910F1A4> > 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>. > I’m having trouble reconciling this with rule #2 above, which states that “Subtype is the supertype of all Types whose instances are subtypes of T, including T itself.” Which one is wrong, or am I confused? One thing I haven’t understood the motivation for exactly is what someone would be able to do with a Proto.self. Dynamic conformance checking? For a concrete T, having its .self seems useful for doing dynamic casts and such, but I don’t understand why for a Proto you need to have both. You did a good job of explaining why T.Protocol and T.Type are different, but not why both of them need to exist. So you could definitely do more to spell out the use-cases here. > 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> Does this potentially expose contravariant type parameters, and is that an issue? (I’m trying to imagine a scenario where you could have an A on the left hand side of an arrow and have that leak out to other clients, but I haven’t had a chance to write much Swift 3 yet, unfortunately.) > 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) > > > 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> Thank you for the hard work you’ve put into this proposal, it’s come a long way! -Colin > > -- > Adrian Zubarev > Sent with Airmail > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org <mailto:swift-evolution@swift.org> > https://lists.swift.org/mailman/listinfo/swift-evolution > <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution