[swift-evolution] [Discussion] Seal `T.Type` into `Type<T>`
Adrian Zubarev
adrian.zubarev at devandartist.com
Fri Jul 15 10:55:52 CDT 2016
You’ve got two things wrong there:
Derived: Base otherwise you cannot cast at all.
w === x //=> FALSE
The reason why this does not work is because it’s impossible to cast a type to an different type with the help of an initializer. As I cleaned up the current implementation I though about replacing init?(casting: Type<T>?) with something like this:
public static func cast<U>(from 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.metatype) == _uniqueIdentifierOf(T.metatype)
// guard isTAny || otherType._metatype is Metatype<T> else {
// return nil
// }
guard otherType._metatype is Metatype<T> else {
return nil
}
// `T` implicitly converted to `Type<T>()`
return unsafeBitCast(otherType, to: T)
}
Your example would become this:
let x = Type<Derived>()
// downcast
let y = Type<Base>.cast(from: x)!
y === x //=> true
// this is safe - upcast
let z = unsafeBitCast(y, to: Type<Derived>())
z === y //=> true
z === x //=> true
let w = Type<Derived>.cast(from: y)!
w === x //=> true
w === y //=> true
w === z //=> true
Global dictionary is not involved here at all. We can change this too and put the reference for all different Type<T> into the dictionary from the designated initializer.
Remember that the global dictionary does only contain unique (dynamic) types, which means we could have this.
[1: Type<Base>(), 2: Type<Derived>()]
Type<Derived>.sharedInstance will give you (2) which you can downcast to Base or Any
The reference will remain pointing to (2) in the global dictionary, which is the correct behavior.
Type<Base>.sharedInstance will give you (1) which you only can downcast to Any but not upcast to Derived
The reason for this is the (dynamic) metatype inside each Type<T> instance.
Here is an example how it works in Swift 2.2:
class Base {}
class Derived: Base {}
let baseMetatype = Base.self
(baseMetatype is Base.Type) == true
(baseMetatype is Any.Type) == true
(baseMetatype is Derived.Type) == false
let derivedMetatype = Derived.self
(derivedMetatype is Base.Type) == true
(derivedMetatype is Any.Type) == true
(derivedMetatype is Derived.Type) == true
Problem solved? Lets tackle next one.
PS: I removed _identifier because now _metatype does the most work.
--
Adrian Zubarev
Sent with Airmail
Am 15. Juli 2016 um 17:12:29, Anton Zhilin (antonyzhilin at gmail.com) schrieb:
Here you are, full example:
let x = Type<Derived>()
// Type<Derived> is not a subtype of Type<Base>, we must construct a new instance of Type<Base>
let y = Type<Base>(casting: x)!
y === x //=> false
// Type<T> are reference types. z will point to the same instance as y
let z = unsafeBitCast(y, to: Type<Derived>())
z === y //=> true
z === x //=> false
// Static and dynamic types are equal here, so we decide to draw from global dictionary
let w = Type<Derived>(casting: y)!
w === x //=> true
w === y //=> false
w === z //=> false
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160715/456679d7/attachment.html>
More information about the swift-evolution
mailing list