[swift-evolution] [Proposal] Refactor Metatypes, repurpose T[dot]self and Mirror

Jaden Geller jaden.geller at gmail.com
Tue Jul 19 16:48:30 CDT 2016


Are both `Type` and `Metatype` covariant with their generic parameter? I imagine they’d have to be, and this should probably be explicitly called out in the proposal. Though user-defined types are always invariant, `Array` has magic behavior that makes it covariant, so I imagine it’s feasible to apply to `Type` and `Metatype`.

> On Jul 19, 2016, at 2:34 PM, Adrian Zubarev via swift-evolution <swift-evolution at swift.org> wrote:
> 
> A few things were already updated (such as reflection rationale from SE–0096) and can be vied here: LINK <https://github.com/DevAndArtist/swift-evolution/blob/refactor_metatypes_repurpose_t_dot_self_and_mirror/proposals/0000-refactor-metatypes-repurpose-t-dot-self-and-mirror.md>
> 
> 
> 
> -- 
> Adrian Zubarev
> Sent with Airmail
> 
> Am 19. Juli 2016 um 22:38:44, Adrian Zubarev (adrian.zubarev at devandartist.com <mailto:adrian.zubarev at devandartist.com>) schrieb:
> 
>> Dear Swift community,
>> 
>> Anton Zhilin and I worked hard past days to finish this proposal, which we started about a weak ago in a different discussion thread. We’d like you to review the proposal before we push a PR for final review.
>> 
>> Thanks to everyone who’s willing to help.
>> 
>> You can read the formatted proposal on GitHub: HERE <https://github.com/DevAndArtist/swift-evolution/blob/refactor_metatypes_repurpose_t_dot_self_and_mirror/proposals/0000-refactor-metatypes-repurpose-t-dot-self-and-mirror.md>
>> Or bellow (Email is markdown formatted):
>> 
>> Refactor Metatypes, repurpose T.self and Mirror
>> 
>> Proposal: SE-NNNN <x-msg://23/nnnn-seal-metatype.md>
>> Author: Adrian Zubarev <https://github.com/DevAndArtist>, Anton Zhilin <https://github.com/Anton3>
>> Status: Awaiting review <x-msg://23/#rationale>
>> Review manager: TBD
>> Introduction
>> 
>> This proposal want to revise metatypes T.Type, repurpose public T.self notation to return a new Type<T> type instance rather than a metatype, merge SE–0101 into Type<T>, rename the global function from SE–0096 to match the changes of this proposal and finally rename current Mirror type to introduce a new (lazy) Mirror type.
>> 
>> Swift-evolution threads:
>> 
>> [Proposal] Refactor Metatypes, repurpose T[dot]self and Mirror <applewebdata://31603E3D-E950-43BC-9218-9F1C91CD413A>
>> [Discussion] Seal T.Type into Type<T> <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160704/023818.html>
>> [Discussion] Can we make .Type Hashable? <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160627/023067.html>
>> GitHub Gist thread:
>> 
>> Refactor metatypes <https://gist.github.com/Anton3/9931463695f1c3263333e18f04f9cd8e>
>> Motivation
>> 
>> The following tasks require metatype-like types:
>> 
>> Explicit specialization of functions and expressing specific static types.
>> Dynamic dispatch of static methods.
>> Representing any value as a tree, for debug purposes.
>> Retrieving and passing around information about dynamic types - Reflection.
>> Current state of things:
>> 
>> [1] is given to metatypes T.Type:
>> 
>> The metatype instance is usually ignored.
>> For example, if you pass Derived.self as Base.self into function taking T.Type, it will work with Base.
>> This raises concerns: are metatypes perfectly suited for that purpose?
>> [2] is also given to metatypes T.Type:
>> 
>> Because they are used so often, it’s tempting to add useful methods to them, but we can’t, because metatypes are not extensible types.
>> [3] is given to Mirror:
>> 
>> Does its name reflect what it’s intended to do?
>> Mirror.DisplayStyle contains optional and set as special cases, but does not contain function at all.
>> Mirror collects all information possible at initialization, while for “true” reflection we want laziness.
>> Mirror allows customization. For example, Array<T> is represented with a field for each of its elements. Do we want this for “true” reflection we want to add in the future?
>> [4] is given to both metatypes T.Type and Mirror:
>> 
>> Metatypes are generic. But do we want genericity in reflection? No, we almost always want to cast to Any.Type.
>> Metatypes are used for getting both static and dynamic sizes.
>> In this context, distinction between generic parameter T and value of metatype instance is unclear.
>> People are confused that Mirror is intended to be used for full-featured reflection, while it does not aim for that.
>> Known issues of metatypes:
>> 
>> Assume this function that checks if an Int type conforms to a specific protocol. This check uses current model of metatypes combined in a generic context:
>> 
>> func intConformsTo<T>(_: T.Type) -> Bool {
>>    return Int.self is T.Type
>> }
>> 
>> intConformsTo(CustomReflectable.self) //=> FALSE
>> [1] When T is a protocol P, T.Type is the metatype of the protocol type itself, P.Protocol. Int.self is not P.self.
>> 
>> [2] There isn’t a way to generically expression P.Type yet.
>> 
>> [3] The syntax would have to be changed in the compiler to get something that behaves like .Type today.
>> 
>> Written by Joe Groff: [1] <https://twitter.com/jckarter/status/754420461404958721> [2] <https://twitter.com/jckarter/status/754420624261472256> [3] <https://twitter.com/jckarter/status/754425573762478080>
>> A possible workaround might look like the example below, but does not allow to decompose P.Type which is a major implementation problem of this proposal:
>> 
>> func intConformsTo<T>(_: T.Type) -> Bool {
>>   return Int.self is T
>> }
>> 
>> intConformsTo(CustomReflectable.Type.self) //=> TRUE
>> This issue was first found and documented as a strange issue in SR–2085 <https://bugs.swift.org/browse/SR-2085>. It also raises the concerns: do we need .Protocol at all?
>> 
>> We can extend this issue and find the second problem by checking agains the metatype of Any:
>> 
>> func intConformsTo<T>(_: T.Type) -> Bool {
>>     return Int.self is T
>> }
>> 
>> intConformsTo(Any.Type.self) //=> TRUE
>> 
>> intConformsTo(Any.self) //=> TRUE
>> As you clearly can see, when using Any the compiler does not require .Type at all.
>> 
>> The third issue will show itself whenever we would try to check protocol relationship with another protocol. Currently there is no way (that we know of) to solve this problem:
>> 
>> protocol P {}
>> protocol R : P {}
>> 
>> func rIsSubtypeOf<T>(_: T.Type) -> Bool {
>>     return R.self is T
>> }
>> 
>> rIsSubtypeOf(P.Type.self) //=> FALSE
>> We also believe that this issue is also the reason why the current gloabl functions sizeof, strideof and alignof make use of generic <T>(_: T.Type) declaration notation instead of (_: Any.Type).
>> 
>> Proposed solution
>> 
>> Metatype<T>:
>> 
>> Revise metatypes in generic context so the old T.Type notation does not produce T.Protocol when a protocol metatype is passed around.
>> Intoduce a distinction between public and internal T.self notation where the internal T.self notation will be renamed to T.metatype.
>> Rename old metatype T.Type notation to Metatype<T>.
>> Make internal T.metatype notation (Buildin - not visible in public Swift) return an instance of Metatype<T>.
>> Public construction of metatypes will look like Type<T>.metatype or T.self.metatype, see below.
>> Metatypes will be used only for dynamic dispatch of static methods, see example below:
>> protocol HasStatic   { static func staticMethod() -> String; init() }
>> struct A : HasStatic { static func staticMethod() -> String { return "I am A" }; init() {} }
>> struct B : HasStatic { static func staticMethod() -> String { return "I am B" }; init() {} }
>> 
>> func callStatic(_ metatype: Metatype<HasStatic>) {
>>     let result = metatype.staticMethod()     
>>     print(result)
>>     let instance = metatype.init()
>>     print(instance)
>> }
>> 
>> let a = Type<A>.metatype
>> let b = Type<B>.metatype
>> callStatic(a)  //=> "I am A" "A()"
>> callStatic(b)  //=> "A am B" "B()"
>> Type<T> API:
>> 
>> T.self will be repurposed to return ab instance of Type<T> that is declared as follows:
>> 
>> public struct Type<T> : Hashable, CustomStringConvertible, CustomDebugStringConvertible {
>>       
>>     /// Creates an instance that reflects `T`.
>>     /// Example: `let type = T.self`
>>     public init()
>>       
>>     /// Returns the contiguous memory footprint of `T`.
>>     ///
>>     /// Does not include any dynamically-allocated or "remote" storage.
>>     /// In particular, `Type<T>.size`, when `T` is a class type, is the
>>     /// same regardless of how many stored properties `T` has.
>>     public static var size: Int { get }
>>       
>>     /// Returns the least possible interval between distinct instances of
>>     /// `T` in memory.  The result is always positive.
>>     public static var stride: Int { get }
>>       
>>     /// Returns the default memory alignment of `T`.
>>     public static var alignment: Int { get }
>>       
>>     /// Returns an instance of `Metatype<T>` from captured `T` literal.
>>     public static var metatype: Metatype<T> { get }
>>       
>>     /// Returns the contiguous memory footprint of `T`.
>>     ///
>>     /// Does not include any dynamically-allocated or "remote" storage.
>>     /// In particular, `Type<T>().size`, when `T` is a class type, is the
>>     /// same regardless of how many stored properties `T` has.
>>     public var size: Int { get }
>>       
>>     /// Returns the least possible interval between distinct instances of
>>     /// `T` in memory.  The result is always positive.
>>     public var stride: Int { get }
>>       
>>     /// Returns the default memory alignment of `T`.
>>     public var alignment: Int { get }
>>       
>>     /// Returns an instance of `Metatype<T>` from captured `T` literal.
>>     public var metatype: Metatype<T> { get }
>>       
>>     /// Hash values are not guaranteed to be equal across different executions of
>>     /// your program. Do not save hash values to use during a future execution.
>>     public var hashValue: Int { get }
>>       
>>     /// A textual representation of `self`.
>>     public var description: String { get }
>>       
>>     /// A textual representation of `self`, suitable for debugging.
>>     public var debugDescription: String { get }
>> }
>> 
>> public func ==<T>(lhs: Type<T>, rhs: Type<T>) -> Bool
>> Size of Type<T> struct equals 0. It will be used for generic function specialization:
>> 
>> func performWithType(_ type: Type<T>)
>> performWithType(Float.self)
>> dynamicMetatype function:
>> 
>> The global dynamicType function from SE–0096 will be renamed to dynamicMetatype and receive the following declaration:
>> 
>> /// Returns a dynamic instance of `Metatype<T>`. A dynamic
>> /// metatype can reflect type `U` where `U : T`.
>> public func dynamicMetatype<T>(_ instance: T) -> Metatype<T>
>> Mirror API:
>> 
>> Rename current Mirror (Swift 2.2) to DebugRepresentation and CustomReflectable to CustomDebugRepresentable.
>> 
>> A completely different Mirror type will be introduced in Swift 3.
>> 
>> Mirror wraps metatypes and allows checking subtype relationships at runtime.
>> Mirror contains dynamic versions of size, stride and alignment.
>> Size of Mirror itself is always 8 bytes, because it only needs to store a single metatype.
>> Mirror provides a starting point for adding fully functional (lazy) reflection in the future.
>> public struct Mirror : Hashable, CustomStringConvertible, CustomDebugStringConvertible {
>> 
>>     /// Creates an instance of `Mirror`, reflecting type, which is
>>     /// reflected by a metatype.
>>     public init(_ metatype: Metatype<Any>)
>>       
>>     /// Creates an instance of `Mirror`, reflecting type `T`
>>     public init<T>(_ type: Type<T>)
>>       
>>     /// Creates an instance of `Mirror`, reflecting   
>>     /// dynamic metatype of a given instance.
>>     public init<T>(reflecting instance: T)
>>       
>>     /// Returns the contiguous memory footprint of reflected metatype.
>>     public var size: Int { get }
>>       
>>     /// Returns the least possible interval between distinct instances of
>>     /// the dynamic type in memory calculated from the reflected dynamic   
>>     /// metatype. The result is always positive.
>>     public var stride: Int { get }
>>       
>>     /// Returns the minimum memory alignment of the reflected dynamic   
>>     /// metatype.
>>     public var alignment: Int { get }
>>       
>>     /// Returns an instance of `Metatype<Any>` from reflected dynamic metatype.
>>     public var metatype: Metatype<Any> { get }
>>       
>>     /// Checks if type reflected by `self` is a subtype of type reflected by another `Mirror`.
>>     public func `is`(_ mirror: Mirror) -> Bool { get }
>>       
>>     /// Checks if type reflected by `self` is a subtype of `T`.
>>     public func `is`<T>(_ type: Type<T>) -> Bool { get }
>>       
>>     /// Checks if type reflected by `self` is a subtype of type reflected by a metatype.
>>     public func `is`<T>(_ metatype: Metatype<T>) -> Bool { get }
>>       
>>     /// Hash values are not guaranteed to be equal across different executions of
>>     /// your program. Do not save hash values to use during a future execution.
>>     public var hashValue: Int { get }
>>       
>>     /// A textual representation of `self`.
>>     public var description: String { get }
>>       
>>     /// A textual representation of `self`, suitable for debugging.
>>     public var debugDescription: String { get }
>> }
>> 
>> public func ==(lhs: Mirror, rhs: Mirror) -> Bool
>> Summary of metatype-like types:
>> 
>> Before
>> 
>> T.Type does three things:
>> Specialization of functions.
>> Dynamic dispatch of static methods.
>> Partial reflection using dynamic casts and functions like sizeof, strideof etc.
>> Mirror does two things:
>> It is primarily intended for use in debugging, like PlaygroundQuickLook.
>> With less success, it can be used for reflection.
>> After
>> 
>> Type<T> does specialization of functions.
>> Mirror does reflection.
>> Metatype<T> does dynamic dispatch of static methods.
>> DebugRepresentation is used in debugging.
>> Detailed design
>> 
>> Possible Implementation:
>> 
>> public struct Type<T> : Hashable, CustomStringConvertible, CustomDebugStringConvertible {
>>       
>>     /// Creates an instance that reflects `T`.
>>     /// Example: `let type = T.self`
>>     public init() {}
>>       
>>     /// Returns the contiguous memory footprint of `T`.
>>     ///
>>     /// Does not include any dynamically-allocated or "remote" storage.
>>     /// In particular, `Type<T>.size`, when `T` is a class type, is the
>>     /// same regardless of how many stored properties `T` has.
>>     public static var size: Int { return _size(of: T.metatype) }
>>       
>>     /// Returns the least possible interval between distinct instances of
>>     /// `T` in memory.  The result is always positive.
>>     public static var stride: Int { return _stride(of: T.metatype) }
>>       
>>     /// Returns the default memory alignment of `T`.
>>     public static var alignment: Int { return _alignment(of: T.metatype) }
>>       
>>     /// Returns an instance of `Metatype<T>` from captured `T` literal.
>>     public static var metatype: Metatype<T> { return T.metatype }
>>       
>>     /// Returns the contiguous memory footprint of `T`.
>>     ///
>>     /// Does not include any dynamically-allocated or "remote" storage.
>>     /// In particular, `Type<T>().size`, when `T` is a class type, is the
>>     /// same regardless of how many stored properties `T` has.
>>     public var size: Int { return Type<T>.size }
>>       
>>     /// Returns the least possible interval between distinct instances of
>>     /// `T` in memory.  The result is always positive.
>>     public var stride: Int { return Type<T>.stride }
>>       
>>     /// Returns the default memory alignment of `T`.
>>     public var alignment: Int { return Type<T>.alignment }
>>       
>>     /// Returns an instance of `Metatype<T>` from captured `T` literal.
>>     public var metatype: Metatype<T> { return Type<T>.metatype }
>>       
>>     /// Hash values are not guaranteed to be equal across different executions of
>>     /// your program. Do not save hash values to use during a future execution.
>>     public var hashValue: Int { return _uniqueIdentifier(for: self.metatype) }
>>       
>>     /// A textual representation of `self`.
>>     public var description: String { return "Type<\(self.metatype)>()" }
>>       
>>     /// A textual representation of `self`, suitable for debugging.
>>     public var debugDescription: String {
>>         return "[" + self.description
>>             + " metatype: \(self.metatype)"
>>             + " size: \(self.size)"
>>             + " stride: \(self.stride)"
>>             + " alignment: \(self.alignment)]"
>>     }
>> }
>> 
>> public func ==<T>(lhs: Type<T>, rhs: Type<T>) -> Bool { return true }
>> 
>> /// Returns a dynamic instance of `Metatype<T>`. A dynamic
>> /// metatype can reflect type `U` where `U : T`.
>> public func dynamicMetatype<T>(_ instance: T) -> Metatype<T> {
>>     return /* implement */
>> }
>> 
>> public struct Mirror : Hashable, CustomStringConvertible, CustomDebugStringConvertible {
>>       
>>     /// Storage for any dynamic metatype.
>>     internal let _metatype: Metatype<Any>
>>       
>>     /// Creates an instance of `Mirror`, reflecting type, which is
>>     /// reflected by a metatype.
>>     public init(_ metatype: Metatype<Any>) {
>>         self._metatype = metatype
>>     }
>>       
>>     /// Creates an instance of `Mirror`, reflecting type `T`
>>     public init<T>(_ type: Type<T>) {
>>         self._metatype = type.metatype
>>     }
>>       
>>     /// Creates an instance of `Mirror`, reflecting   
>>     /// dynamic type of a given instance.
>>     public init<T>(reflecting instance: T) {
>>         self._metatype = dynamicMetatype(instance)
>>     }
>>       
>>     /// Returns the contiguous memory footprint of reflected metatype.
>>     public var size: Int { return _size(of: self._metatype) }
>>       
>>     /// Returns the least possible interval between distinct instances of
>>     /// the dynamic type in memory calculated from the reflected dynamic   
>>     /// metatype. The result is always positive.
>>     public var stride: Int { return _stride(of: self._metatype) }
>>       
>>     /// Returns the minimum memory alignment of the reflected dynamic   
>>     /// metatype.
>>     public var alignment: Int { return _alignment(of: self._metatype) }
>>       
>>     /// Returns an instance of `Metatype<T>` from reflected dynamic metatype.
>>     public var metatype: Any.Type { return self._metatype }
>>       
>>     /// Checks if type reflected by `self` is a subtype of type reflected by another `Mirror`.
>>     public func `is`(_ mirror: Mirror) -> Bool {
>>         return _is(metatype: self._metatype, also: mirror.metatype)
>>     }
>>       
>>     /// Checks if type reflected by `self` is a subtype of `T`.
>>     public func `is`<T>(_ type: Type<T>) -> Bool {
>>         return _is(metatype: self._metatype, also: type.metatype)
>>     }
>>       
>>     /// Checks if type reflected by `self` is a subtype of type reflected by a metatype.
>>     public func `is`<T>(_ metatype: Metatype<T>) -> Bool {
>>         return _is(metatype: self._metatype, also: metatype)
>>     }
>>       
>>     /// Hash values are not guaranteed to be equal across different executions of
>>     /// your program. Do not save hash values to use during a future execution.
>>     public var hashValue: Int { return _uniqueIdentifier(for: self._metatype) }
>>       
>>     /// A textual representation of `self`.
>>     public var description: String { return "Mirror(\(self._metatype))" }
>>       
>>     /// A textual representation of `self`, suitable for debugging.
>>     public var debugDescription: String {
>>         return "[" + self.description
>>             + " metatype: \(self._metatype)"
>>             + " size: \(self.size)"
>>             + " stride: \(self.stride)"
>>             + " alignment: \(self.alignment)]"
>>     }
>> }
>> 
>> public func ==(lhs: Mirror, rhs: Mirror) -> Bool {
>>     return lhs.hashValue == rhs.hashValue
>> }
>> Internal functions:
>> 
>> These functions were used in the implementation above to calculate metatype related informations.
>> 
>> _size(of:), _stride(of:) and _alignment(of:) functions need some additional tweaking so they will work with any matatype stored in an instance of Metatype<Any> rather than a dynamic <T>(of metatype: Metatype<T>) variant, which is not suitable for calculations needed in Mirror.
>> 
>> _uniqueIdentifier(for:) function is fully implemented and should just work when the current generic issue with .Protocol metatypes is resolved.
>> 
>> _is(metatype:also:) relies on the resolved .Protocol issue. The final implementation should allow to check type relationship between two different metatype instances.
>> 
>> internal func _size(of metatype: Metatype<Any>) -> Int {
>>     // Fix this to allow any metatype
>>     return Int(Builtin.sizeof(metatype))
>> }
>> 
>> internal func _stride(of metatype: Metatype<Any>) -> Int {
>>     // Fix this to allow any metatype
>>     return Int(Builtin.strideof_nonzero(metatype))
>> }
>> 
>> internal func _alignment(of metatype: Metatype<Any>) -> Int {
>>     // Fix this to allow any metatype
>>     return Int(Builtin.alignof(metatype))
>> }
>> 
>> internal func _uniqueIdentifier(for metatype: Metatype<Any>) -> Int {
>>     let rawPointerMetatype = unsafeBitCast(metatype, to: Builtin.RawPointer.metatype)
>>     return Int(Builtin.ptrtoint_Word(rawPointerMetatype))
>> }
>> 
>> internal func _is(metatype m1: Metatype<Any>, also m2: Metatype<Any>) -> Bool {
>>     return /* implement - checks type ralationshiop `M1 : M2` and `M1 == M2` */
>> }
>> Summary of Steps:
>> 
>> Revise metatypes in generic context so the old T.Type notation does not produce T.Protocol when a protocol metatype is passed around.
>> Make public T.self notation return an instance of Type<T>.
>> Rename internal T.self notation to T.metatype (Buildin - not visible in public Swift).
>> Rename old metatype T.Type notation to Metatype<T>.
>> Make internal T.metatype notation return an instance of Metatype<T>.
>> Revise APIs with current T.Type notation to use Type<T> and in few edge cases Metatype<T>.
>> Move size, stride and alignment from SE–0101 to Type<T>.
>> Provide a concrete declaration for SE–0096 and rename it to dynamicMetatype.
>> Rename current Mirror type (Swift 2.2) to DebugRepresentation and CustomReflectable to CustomDebugRepresentable.
>> Introduce a new Mirror type that is intended to replace metatypes for most use cases and extended with reflection in a future release.
>> Impact on existing code
>> 
>> This is a source-breaking change that can be automated by a migrator.
>> 
>> The following steps reflects our suggestion of the migration process, these can differ from the final migration process implemented by the core team if this proposal will be accepted:
>> 
>> T.Type → Metatype<T>
>> T.self → Type<T>.metatype
>> Mirror → DebugRepresentation
>> CustomReflectable → CustomDebugRepresentable
>> customMirror → customDebugRepresentation
>> sizeof(T.self) → Type<T>.size
>> sizeof(metatype) → Mirror(metatype).size
>> Migrating metatype variables to use Type<T> and Mirror
>> 
>> Metatype<T> is a safe default for transition, but we want to discourage usage of metatypes. In some cases, we can provide fix-its to replace usage of Metatype<T> with Type<T> or Mirror.
>> 
>> To change type of a variable named type from Metatype<T> to Type<T>:
>> 
>> Replace its type with Type<T>.
>> Use the migration patterns below.
>> If some use case does not match any of these, the variable cannot be migrated to type Type<T>.
>> Migration patterns:
>> 
>> type = T.self.metatype → type = T.self
>> type = U.self.metatype where U != T → Automatic migration impossible
>> type = Type<T>.metatype → type = T.self
>> type = Type<U>.metatype where U != T → Automatic migration impossible
>> type = otherMetatype where otherMetatype: Metatype<T> → type = T.self
>> type = otherMetatype where otherMetatype: Metatype<U>, U != T → Automatic migration impossible
>> type = mirror.metatype where mirror: Mirror → Automatic migration impossible
>> otherMetatype = type where otherMetatype: Metatype<U> → otherMetatype = Type<T>.metatype
>> Mirror(type) → Mirror(type)
>> type as otherMetatype where otherMetatype: Metatype<U> → type.metatype as metatype<U>
>> type as? otherMetatype → Automatic migration impossible
>> type as! otherMetatype → Automatic migration impossible
>> type is otherMetatype → Automatic migration impossible
>> How to change type of a variable named type from Metatype<T> to Mirror:
>> 
>> Replace its type with Mirror.
>> Use the migration patterns below.
>> If some use case does not match any of these, the variable cannot be migrated to type Mirror.
>> Migration patterns:
>> 
>> type: Metatype<T> → type: Mirror
>> type = U.self.metatype → type = Mirror(U.self)
>> type = Type<U>.metatype → type = Mirror(U.self)
>> type = otherMetatype → type = Mirror(otherMetatype)
>> type = mirror.metatype where mirror: Mirror → type = mirror
>> otherMetatype = type → otherMetatype = type.metatype
>> Mirror(type) → type
>> type as otherMetatype → type.metatype as! otherMetatype
>> type as? otherMetatype → type.metatype as? otherMetatype
>> type as! otherMetatype → type.metatype as! otherMetatype
>> type is otherMetatype → type.is(otherMetatype)
>> We can also migrate metatype parameters of a function, where assignment means passing an argument to that function.
>> 
>> In two cases we can apply these automatically:
>> 
>> If a generic function takes parameter Metatype<T>, then we can try to replace Metatype<T> with Type<T>.
>> We can try to replace usage of Metatype<Any> (aka AnyMetatype) with Mirror.
>> Alternatives considered
>> 
>> After refactoring metatypes it is assumed that any metatype can be stored inside an instance of Metatype<Any>. If that will not be the case, then we propose to introduce a new standalone type for explained behavior. That type could be named as AnyMetatype. Therefore any type marked with Metatype<Any> in this proposal will become AnyMetatype.
>> 
>> If the community and the core team are strongly against the repurposing of Mirror we’d like to consider to merge the proposed functionality into a single type. For such a change we do believe Type<T> might be the right type here. However this introduces further complications such as storing dynamic metatypes inside of Type<T> and a few other that we don’t want go in detail here.
>> 
>> Future directions
>> 
>> Remove public .self:
>> 
>> When SE–0090 is accepted we will remove T.self notation and only have type literals like T.
>> 
>> Examples:
>> 
>> let someInstance = unsafeBitCast(1.0, to: Int)
>> let dynamicSize = Mirror(reflecting: someInstance).size
>> Then we can add Type(_: Type<T>) initializer for disambiguation:
>> 
>> Int.self.size     // Works fine with this proposal, but what if we drop `.self`?
>> Int.size          // Will be an error after dropping `.self`.
>> Type<Int>().size  // Would work, but looks odd.
>> Type(Int).size    // This version looks much better.
>> When combined with this proposal, the result will be to eliminate all ‘magical’ members that existed in the language:
>> 
>> .dynamicType
>> .Type
>> .self
>> There is also Self, but it acts like an associatedtype.
>> 
>> Extend Mirror with reflection functionality:
>> 
>> Reflection is one of stated goals for Swift 4. With this proposal, adding reflection becomes as simple as extending Mirror. For example, we could add the following computed property:
>> 
>> typealias FieldDescriptor = (name: String, type: Mirror, getter: (Any) -> Any, setter: (inout Any, Any) -> ())
>> var fields: [FieldDescriptor] { get }
>> 
>> 
>> -- 
>> Adrian Zubarev
>> Sent with Airmail
> 
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160719/c82c5eba/attachment.html>


More information about the swift-evolution mailing list