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


(Adrian Zubarev) #1

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

Or bellow (Email is markdown formatted):

Refactor Metatypes, repurpose T.self and Mirror

Proposal: SE-NNNN
Author: Adrian Zubarev, Anton Zhilin
Status: Awaiting review
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
[Discussion] Seal T.Type into Type<T>
[Discussion] Can we make .Type Hashable?
GitHub Gist thread:

Refactor metatypes
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] [2] [3]
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. 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


(Adrian Zubarev) #2

A few things were already updated (such as reflection rationale from SE–0096) and can be vied here: LINK

···

--
Adrian Zubarev
Sent with Airmail

Am 19. Juli 2016 um 22:38:44, Adrian Zubarev (adrian.zubarev@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

Or bellow (Email is markdown formatted):

Refactor Metatypes, repurpose T.self and Mirror

Proposal: SE-NNNN
Author: Adrian Zubarev, Anton Zhilin
Status: Awaiting review
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
[Discussion] Seal T.Type into Type<T>
[Discussion] Can we make .Type Hashable?
GitHub Gist thread:

Refactor metatypes
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] [2] [3]
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. 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


(Jaden Geller) #3

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@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@devandartist.com <mailto:adrian.zubarev@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Karl) #4

In general a strong +1 because I’ve been bumping against the .Protocol problem several times.

I’m not sure about the name “Metatype” and the relationship with “Type” - particularly with the protocol example, it isn’t obvious to a novice user why it’s like this or what these mean.

You say that you want this for Swift 3, and it seems like you’ve done quite a lot of research in to the implementation details. When you talk about “internal” metatypes, do you mean that this information already exists, and that the majority of the implementation work would be to expose it?

Karl

···

On 19 Jul 2016, at 23:34, Adrian Zubarev via swift-evolution <swift-evolution@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@devandartist.com <mailto:adrian.zubarev@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://5/nnnn-seal-metatype.md>
Author: Adrian Zubarev <https://github.com/DevAndArtist>, Anton Zhilin <https://github.com/Anton3>
Status: Awaiting review <x-msg://5/#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://78072DD1-B9B0-447C-933E-FF9BC7AC6FCE>
[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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Adrian Zubarev) #5

@Karl: Thank you for your feedback:

I’m not sure about the name “Metatype” and the relationship with “Type” - particularly with the protocol example, it isn’t obvious to a novice user why it’s like this or what these mean.
Do you mean the example from known issues where in a generic context the metatype will become T.Protocol instead of expected T.Type? We haven’t dug that far in Swifts C++ code so we could tell the exact need of it.

In my personal experience with Swift, I haven’t written anything that would make use of .Protocol and I also haven’t seen anyone doing this:

protocol P {}

P.self is P.Protocol //=> TRUE
You say that you want this for Swift 3, and it seems like you’ve done quite a lot of research in to the implementation details. When you talk about “internal” metatypes, do you mean that this information already exists, and that the majority of the implementation work would be to expose it?
I believe you mean when we talked about T.metatype:

Currently T.self does this job already.
But we want to repurpose it to return a lightweight instance of Type<T> instead.
That requires a distinctions between the new public T.self notation and the sealed T.metatype notation that previously was T.self in general.
For the research, as not a compiler expert, we had something like this:

protocol P {}
protocol R : P {}

class A : P {}
class B : R {}

let b = B()
let hide: Any = b
let dynamicMetatype = hide.dynamicType // Any.Type (Any.self??)

dynamicMetatype is P.Type // true
dynamicMetatype is R.Type // true
dynamicMetatype is A.Type // false - WHY??
dynamicMetatype is B.Type // true
dynamicMetatype is Any.Type // true

public func !=<T : Hashable, U, V>(lhs: T<U>, rhs: T<V>) -> Bool {
    return lhs.hashValue != rhs.hashValue
}

print(new)
let c = unsafeBitCast(new, to: C.Type.self)

class A {
    var value1: Int = 35
    var value2: Int = 35
    var value3: Int = 35
    var value4: Int = 35
    var value5: Int = 35
}

struct B {
    var value1: Int = 35
    var value2: Int = 35
    var value3: Int = 35
    var value4: Int = 35
    var value5: Int = 35
}

enum C {
    case a
    case b
    case c
    case d
     
    var value1: Int { return 35 }
    var value2: Int { return 35 }
    var value3: Int { return 35 }
    var value4: Int { return 35 }
    var value5: Int { return 35 }
}

protocol D {
    var value1: Int { get }
    var value2: Int { get }
    var value3: Int { get }
    var value4: Int { get }
    var value5: Int { get }
    var value6: Int { get }
}

let metatypeA = A.self // A.Type
let metatypeB = B.self // B.Type
let metatypeC = C.self // C.Type
let metatypeD = D.self // D.Protocol
let metatypeAny = Any.self // protocol<>.Protocol

let metatypeA_ = A.Type.self // A.Type.Type
let metatypeB_ = B.Type.self // B.Type.Type
let metatypeC_ = C.Type.self // C.Type.Type
let metatypeD_ = D.Type.self // D.Type.Protocol
let metatypeAny_ = Any.Type.self // protocol<>.Protocol

sizeof(metatypeA) // 8
sizeof(metatypeB) // 40
sizeof(metatypeC) // 1
sizeof(metatypeD) // 40
sizeof(metatypeAny) // 32

sizeof(A.self) // 8
sizeof(B.self) // 40
sizeof(C.self) // 1
sizeof(D.self) // 40
sizeof(Any.self) // 32

sizeof(metatypeA_) // 8
sizeof(metatypeB_) // 0
sizeof(metatypeC_) // 0
sizeof(metatypeD_) // 16
sizeof(metatypeAny_) // 8

sizeof(A.Type.self) // 8
sizeof(B.Type.self) // 0
sizeof(C.Type.self) // 0
sizeof(D.Type.self) // 16
sizeof(Any.Type.self)// 8 <----

let q1: Any.Type = A.self // A.Type
let q2: Any.Type = B.self // B.Type
let q3: Any.Type = C.self // C.Type
let q4: Any.Type = D.self // D.Protocol
let q5: Any.Type = Any.self // protocol<>.Protocol
let q6: Any.Type = A.Type.self // A.Type.Type
let q7: Any.Type = B.Type.self // B.Type.Type
let q8: Any.Type = C.Type.self // C.Type.Type
let q9: Any.Type = D.Type.self // D.Type.Protcol
let q0: Any.Type = Any.Type.self // protocol<>.Type.Protcol

let q10: Any.Type = Metatype<A>.self // A.Type.Type
let q11: Any.Type = Metatype<B>.self // B.Type.Type
let q12: Any.Type = Metatype<C>.self // C.Type.Type
let q13: Any.Type = Metatype<D>.self // D.Protocol.Type
let q14: Any.Type = Metatype<Any>.self // protocol<>.Protocol.Type

let q15: Metatype<D>.Type = Metatype<D>.self

// Everything is 8 byte
sizeofValue(q1)
sizeofValue(q2)
sizeofValue(q3)
sizeofValue(q4)
sizeofValue(q5)
sizeofValue(q6)
sizeofValue(q7)
sizeofValue(q8)
sizeofValue(q9)
sizeofValue(q0)

sizeofValue(q10)
sizeofValue(q11)
sizeofValue(q12)
sizeofValue(q13)
sizeofValue(q14)

sizeofValue(q15)

sizeofValue(metatypeA)

// 0 bytes
sizeofValue(metatypeB)
sizeofValue(metatypeC)
sizeofValue(metatypeD)
sizeofValue(metatypeAny)

// 8 bytes
sizeofValue(A.self)

// 0 bytes
sizeofValue(B.self)
sizeofValue(C.self)
sizeofValue(D.self)
sizeofValue(Any.self)

// 8 bytes
sizeofValue(metatypeA_)

// 0 bytes
sizeofValue(metatypeB_)
sizeofValue(metatypeC_)
sizeofValue(metatypeD_)
sizeofValue(metatypeAny_)

// 8 bytes
sizeofValue(A.Type.self)

// 0 bytes
sizeofValue(B.Type.self)
sizeofValue(C.Type.self)
sizeofValue(D.Type.self)
sizeofValue(Any.Type.self)

// 8 bytes
sizeofValue(Metatype<A>.self)

// 0 bytes
sizeofValue(Metatype<B>.self)
sizeofValue(Metatype<C>.self)
sizeofValue(Metatype<D>.self)
sizeofValue(Metatype<Any>.self)
And also something like this (You can find the full experiment Gist here: LINK):

protocol P {}
protocol R : P {}
class A : P {}
class B : A, R {}

P.self is Any.Type //=> always true

// STRANGE ISSUE: does not require `.Type`
Mirror(P.self).is(Any.self) //=> true
Mirror(P.self).is(Type<Any>()) //=> true
Mirror(P.self).is(Type<Any>.metatype) //=> true

P.self is Any.Protocol //=> false

Mirror(P.self).is(Any.Type.self) //=> true
Mirror(P.self).is(Type<Any.Type>()) //=> true
Mirror(P.self).is(Type<Any.Type>.metatype) //=> true

P.self is P.Type //=> true

Mirror(P.self).is(P.self) //=> true
Mirror(P.self).is(Type<P>()) //=> true
Mirror(P.self).is(Type<P>.metatype) //=> true

R.self is Any.Type //=> always true

// STRANGE ISSUE: does not require `.Type`
Mirror(R.self).is(Any.self) //=> true
Mirror(R.self).is(Type<Any>()) //=> true
Mirror(R.self).is(Type<Any>().metatype) //=> true

// KNOWN ISSUE: Without `.Type` we'd have `.Protocol`
// result -> FALSE
Mirror(R.self).is(Any.Type.self) //=> true
Mirror(R.self).is(Type<Any.Type>()) //=> true
Mirror(R.self).is(Type<Any.Type>.metatype) //=> true

// KNOWN ISSUE: I couldn't implemt it so it does
// work as expected
R.self is P.Type //=> true

Mirror(R.self).is(P.self) //=> false
Mirror(R.self).is(Type<P>()) //=> false
Mirror(R.self).is(Type<P>.metatype) //=> false

// KNOWN ISSUE: mirror a protocol and check
// against another protocol with `.Type` fails
Mirror(R.self).is(P.Type.self) //=> false
Mirror(R.self).is(Type<P.Type>()) //=> false
Mirror(R.self).is(Type<P.Type>.metatype) //=> false

R.self is R.Type //=> true

// STRANGE ISSUE: does not require `.Type`
Mirror(R.self).is(R.self) //=> true
Mirror(R.self).is(Type<R>()) //=> true
Mirror(R.self).is(Type<R>.metatype) //=> true

// KNOWN ISSUE: mirror a protocol and check
// against another protocol with `.Type` fails
Mirror(R.self).is(R.Type.self) //=> false
Mirror(R.self).is(Type<R.Type>()) //=> false
Mirror(R.self).is(Type<R.Type>.metatype) //=> false

A.self is Any.Type //=> always true

// STRANGE ISSUE: does not require `.Type`
Mirror(A.self).is(Any.self) //=> true
Mirror(A.self).is(Type<Any>()) //=> true
Mirror(A.self).is(Type<Any>.metatype) //=> true

// KNOWN ISSUE: Without `.Type` we'd have `.Protocol`
// result -> FALSE
Mirror(A.self).is(Any.Type.self) //=> true
Mirror(A.self).is(Type<Any.Type>()) //=> true
Mirror(A.self).is(Type<Any.Type>.metatype) //=> true

A.self is P.Type //=> always true

// KNOWN ISSUE: Without `.Type` we'd have `.Protocol`
// result -> FALSE
Mirror(A.self).is(P.Type.self) //=> true
Mirror(A.self).is(Type<P.Type>()) //=> true
Mirror(A.self).is(Type<P.Type>.metatype) //=> true

B.self is Any.Type //=> always true

// STRANGE ISSUE: does not require `.Type`
Mirror(B.self).is(Any.self) //=> true
Mirror(B.self).is(Type<Any>()) //=> true
Mirror(B.self).is(Type<Any>.metatype) //=> true

// KNOWN ISSUE: Without `.Type` we'd have `.Protocol`
// result -> FALSE
Mirror(B.self).is(Any.Type.self) //=> true
Mirror(B.self).is(Type<Any.Type>()) //=> true
Mirror(B.self).is(Type<Any.Type>.metatype) //=> true

B.self is P.Type //=> always true

// KNOWN ISSUE: Without `.Type` we'd have `.Protocol`
// result -> FALSE
Mirror(B.self).is(P.Type.self) //=> true
Mirror(B.self).is(Type<P.Type>()) //=> true
Mirror(B.self).is(Type<P.Type>.metatype) //=> true

B.self is R.Type //=> always true

// KNOWN ISSUE: Without `.Type` we'd have `.Protocol`
// result -> FALSE
Mirror(B.self).is(R.Type.self) //=> true
Mirror(B.self).is(Type<R.Type>()) //=> true
Mirror(B.self).is(Type<R.Type>.metatype) //=> true

B.self is A.Type //=> always true

Mirror(B.self).is(A.self) //=> true
Mirror(B.self).is(Type<A>()) //=> true
Mirror(B.self).is(Type<A>.metatype) //=> true

···

--
Adrian Zubarev
Sent with Airmail

Am 20. Juli 2016 um 04:30:38, Karl (razielim@gmail.com) schrieb:

In general a strong +1 because I’ve been bumping against the .Protocol problem several times.

I’m not sure about the name “Metatype” and the relationship with “Type” - particularly with the protocol example, it isn’t obvious to a novice user why it’s like this or what these mean.

You say that you want this for Swift 3, and it seems like you’ve done quite a lot of research in to the implementation details. When you talk about “internal” metatypes, do you mean that this information already exists, and that the majority of the implementation work would be to expose it?

Karl


(Adrian Zubarev) #6

I’m not sure about the name “Metatype” and the relationship with “Type”
About the name. Metatypes are documented but they are types of its own kind and are mostly used in cases like:

// Current Swift 2.2

metatype.staticFunction // also equivalent to T.staticFunction
metatype.staticComputedProperty // also equivalent to T.staticComputedProperty
metatype.init // also equivalent to T.init

// And without metatypes like they are build in Swift (at least T.Type variant):
// We couldn't build these neat looking api's like
struct A {
    static var neat: SomethingNeat.Type {
        return SomethingNeat.self
    }
}
struct SomethingNeat {
     
    init() {}
}

let neat: SomethingNeat = A.neat.init()
With this proposal we would like to discourage the most (not every) use of metatypes and make their existence and functionality crystal clear for everyone.

However, Type<T> captures the type literal, it’s lightweight because it’s completely lazy and has no stored properties. It also provides an access to the metatype whenever you may need it (mostly in cases of API design, so do I believe) and type related footprints like size, stride and alignment which are calculated internally from the metatype of the captured T literal.

And something like Int.self will finally become Hashable which is really handy.

···

--
Adrian Zubarev
Sent with Airmail

Am 20. Juli 2016 um 04:30:38, Karl (razielim@gmail.com) schrieb:

I’m not sure about the name “Metatype” and the relationship with “Type”