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 ([email protected]) 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
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to