[swift-evolution] [Discussion] Seal `T.Type` into `Type<T>`

Adrian Zubarev adrian.zubarev at devandartist.com
Fri Jul 15 14:09:55 CDT 2016

Not sure what you have tried to solve here. sharedInstance works just fine in my test implementation with Xcode 8 beta 2:

Here is a portion of the implementation that does compile and work as expected, at least I couldn’t find any bugs.

WARNING: the implementation we should tackle is here: https://gist.github.com/DevAndArtist/a5744f21107812b2d4e6baee2c55e0bf

It differs how this is done in the following example:

internal func _uniqueIdentifierOf(_ metatype: Any.Type) -> Int {
    return ObjectIdentifier.init(metatype).hashValue

public typealias Metatype<T> = T.Type
public typealias AnyMetatype = Any.Type

public final class Type<T> : Hashable {
    internal let _metatype: AnyMetatype
    internal init(metatype: AnyMetatype) {

        // check explicitly if `T` is `Any`
        let tIsAny = _uniqueIdentifierOf(Any.self) == _uniqueIdentifierOf(T.self)
        guard tIsAny || metatype is T.Type else {
            fatalError("'metatype' is not an instace of 'Metatype<T>'")
        self._metatype = metatype
    internal convenience init() {
        self.init(metatype: T.self)
    public static func cast<U>(_ optionalType: Type<U>?) -> Type<T>? {
        guard let otherType = optionalType else { return nil }
        // Check if we can up- or downcast the metatype from `otherType` to `Metatype<T>`
        // Bug: SR-2085
        // Workaround: Check explicitly if `T` is `Any`
        let isTAny = _uniqueIdentifierOf(Any.self) == _uniqueIdentifierOf(T.self)
        guard isTAny || otherType._metatype is Metatype<T> else {
            return nil

        return unsafeBitCast(otherType, to: Type<T>.self)
    public var metatype: T.Type {
        return unsafeBitCast(self._metatype, to: T.Type.self)
    public static var metatype: T.Type { return T.self }
    public var hashValue: Int { return _uniqueIdentifierOf(self._metatype) }

public func ==<T, U>(lhs: Type<T>, rhs: Type<U>) -> Bool {
    return lhs.hashValue == rhs.hashValue

internal var _typeStorage = Set<Type<Any>>()

extension Type {
    internal static var sharedInstance: Type<T> {
        let identifier = _uniqueIdentifierOf(Type<T>.metatype)
        let typeFromStorage = _typeStorage.first(where: { $0.hashValue == identifier })
        if let type = Type<T>.cast(typeFromStorage) {
            return type
        let newType = Type<T>()
        // downcast `T` to `Any`
        if let type = Type<Any>.cast(newType) {
        return newType


print(_typeStorage) // [Type<Swift.Int>]


print(_typeStorage) // [Type<Swift.Int>, Type<Swift.String>]

class A {}
class B: A {}


print(_typeStorage) // [Type<Swift.Int>, Type<B>, Type<Swift.String>]


print(_typeStorage) // [Type<Swift.String>, Type<Swift.Int>, Type<A>, Type<B>]

Adrian Zubarev
Sent with Airmail

Am 15. Juli 2016 um 19:58:28, Anton Zhilin (antonyzhilin at gmail.com) schrieb:

Consider what I said above, I feel like we should tackle this:

init(_ copy: Type<T>) - to keep equality of  
Type<T> references

make all initializer internal and as exchange make  
sharedInstance public.
This would ensure that you will always get a reference from the type storage, and that there can only exist one for each (dynamic) metatype.

I have another idea:

// No uniqueness guarantee
internal class _Type<T> {
    var _metatype: Metatype<T>

    init(_: AnyMetatype)
    init?<U>(casting: Type<U>)

    // Instead of a global dictionary
    class var sharedInstance: _Type<T>

// Uniqueness guarantee
public struct Type<T> {
    internal var impl: _Type<T>

    public init()
    public init(_: AnyMetatype)
    public init?<U>(casting: Type<U>)
I can’t foresee the future, so I’m wondering if the type may mutate somehow when reflections are added?

I don’t think so. If added at all, types should only be able to be created using some kind of builder:

let builder = TypeBuilder(name: "Person", kind: .struct)
builder.addField(name: "", type: Int.self)
let typeRef = builder.create()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160715/ef9e8617/attachment.html>

More information about the swift-evolution mailing list