[swift-evolution] [Discussion] Seal `T.Type` into `Type<T>`
Adrian Zubarev
adrian.zubarev at devandartist.com
Fri Jul 15 14:24:54 CDT 2016
To summarize a few things that this proposal should change:
Make public .self construct Type<T> via Type<T>.sharedInstance
Let SE–0090 do the rest for public .self drop
Rename type for metatypes T.Type to Metatype<T> (or at least to T.Metatype)
Rename internal .self to .metatype which will return an instance of Metatype<T>
Use Type<T> instead of current T.Type
Implement public func dynamicType<T>(_ instance: T) -> Type<T> using internal _typeStorage. SE–0096
public func dynamicType<T>(_ instance: T) -> Type<T> {
let dynamicMetatype = /* extract dynamic metatype from the `instance` */
let identifier = _uniqueIdentifierOf(dynamicMetatype)
// Check if the type storage contains an instance of our dynamicType
if let type = _typeStorage.first(where: { $0.hashValue == identifier }) {
// We only need to switch `Any` to `T` but keep the reference
// `Type<T>` is implicitly converted to `Type<Type<T>>()`
return unsafeBitCast(type, to: Type<T>)
}
// Create and store an instance of `Type<T>`
var type = Type<T>.sharedInstance
// Check if the identifier for our dynamic metatype is equivalent
// to the created instance, which implies `dynamicMetatype == T`
if type.hashValue == identifier {
return type
}
// If the identifiers are not equivalent then
// T is probably downcasted from dynamicMetatype
type = Type<Any>(metatype: dynamicMetatype)
_typeStorage.insert(type)
// `Type<T>` is implicitly converted to `Type<Type<T>>()`
return unsafeBitCast(type, to: Type<T>)
}
Combine SE–0101
--
Adrian Zubarev
Sent with Airmail
Am 15. Juli 2016 um 21:10:01, Adrian Zubarev (adrian.zubarev at devandartist.com) schrieb:
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/8143f529/attachment.html>
More information about the swift-evolution
mailing list