[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) {
             
            _typeStorage.insert(type)
        }
        return newType
    }
}

Type<Int>.sharedInstance
Type<Int>.sharedInstance
Type<Int>.sharedInstance
Type<Int>.sharedInstance

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

Type<String>.sharedInstance

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

class A {}
class B: A {}

Type<B>.sharedInstance
Type<B>.sharedInstance

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

Type<A>.sharedInstance

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:

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

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()
    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