[swift-evolution] [Proposal] Refactor Metatypes, repurpose T[dot]self and Mirror

Adrian Zubarev adrian.zubarev at devandartist.com
Wed Jul 20 03:28:30 CDT 2016


@Karl: Thank you for your feedback:

I’m not sure about the name “Metatype” and the relationship with “Type” - particularly with the protocol example, it isn’t obvious to a novice user why it’s like this or what these mean.
Do you mean the example from known issues where in a generic context the metatype will become T.Protocol instead of expected T.Type? We haven’t dug that far in Swifts C++ code so we could tell the exact need of it.

In my personal experience with Swift, I haven’t written anything that would make use of .Protocol and I also haven’t seen anyone doing this:

protocol P {}

P.self is P.Protocol //=> TRUE
You say that you want this for Swift 3, and it seems like you’ve done quite a lot of research in to the implementation details. When you talk about “internal” metatypes, do you mean that this information already exists, and that the majority of the implementation work would be to expose it?
I believe you mean when we talked about T.metatype:

Currently T.self does this job already.
But we want to repurpose it to return a lightweight instance of Type<T> instead.
That requires a distinctions between the new public T.self notation and the sealed T.metatype notation that previously was T.self in general.
For the research, as not a compiler expert, we had something like this:

protocol P {}
protocol R : P {}

class A : P {}
class B : R {}

let b = B()
let hide: Any = b
let dynamicMetatype = hide.dynamicType // Any.Type (Any.self??)

dynamicMetatype is P.Type // true
dynamicMetatype is R.Type // true
dynamicMetatype is A.Type // false - WHY??
dynamicMetatype is B.Type // true
dynamicMetatype is Any.Type // true


public func !=<T : Hashable, U, V>(lhs: T<U>, rhs: T<V>) -> Bool {
    return lhs.hashValue != rhs.hashValue
}


print(new)
let c = unsafeBitCast(new, to: C.Type.self)


class A {
    var value1: Int = 35
    var value2: Int = 35
    var value3: Int = 35
    var value4: Int = 35
    var value5: Int = 35
}

struct B {
    var value1: Int = 35
    var value2: Int = 35
    var value3: Int = 35
    var value4: Int = 35
    var value5: Int = 35
}

enum C {
    case a
    case b
    case c
    case d
     
    var value1: Int { return 35 }
    var value2: Int { return 35 }
    var value3: Int { return 35 }
    var value4: Int { return 35 }
    var value5: Int { return 35 }
}

protocol D {
    var value1: Int { get }
    var value2: Int { get }
    var value3: Int { get }
    var value4: Int { get }
    var value5: Int { get }
    var value6: Int { get }
}

let metatypeA = A.self           // A.Type
let metatypeB = B.self           // B.Type
let metatypeC = C.self           // C.Type
let metatypeD = D.self           // D.Protocol
let metatypeAny = Any.self       // protocol<>.Protocol

let metatypeA_ = A.Type.self     // A.Type.Type
let metatypeB_ = B.Type.self     // B.Type.Type
let metatypeC_ = C.Type.self     // C.Type.Type
let metatypeD_ = D.Type.self     // D.Type.Protocol
let metatypeAny_ = Any.Type.self // protocol<>.Protocol

sizeof(metatypeA)    // 8
sizeof(metatypeB)    // 40
sizeof(metatypeC)    // 1
sizeof(metatypeD)    // 40
sizeof(metatypeAny)  // 32

sizeof(A.self)       // 8
sizeof(B.self)       // 40
sizeof(C.self)       // 1
sizeof(D.self)       // 40
sizeof(Any.self)     // 32

sizeof(metatypeA_)   // 8
sizeof(metatypeB_)   // 0
sizeof(metatypeC_)   // 0
sizeof(metatypeD_)   // 16
sizeof(metatypeAny_) // 8

sizeof(A.Type.self)  // 8
sizeof(B.Type.self)  // 0
sizeof(C.Type.self)  // 0
sizeof(D.Type.self)  // 16
sizeof(Any.Type.self)// 8 <----

let q1: Any.Type = A.self              // A.Type
let q2: Any.Type = B.self              // B.Type
let q3: Any.Type = C.self              // C.Type
let q4: Any.Type = D.self              // D.Protocol
let q5: Any.Type = Any.self            // protocol<>.Protocol
let q6: Any.Type = A.Type.self         // A.Type.Type
let q7: Any.Type = B.Type.self         // B.Type.Type
let q8: Any.Type = C.Type.self         // C.Type.Type
let q9: Any.Type = D.Type.self         // D.Type.Protcol
let q0: Any.Type = Any.Type.self       // protocol<>.Type.Protcol


let q10: Any.Type = Metatype<A>.self   // A.Type.Type
let q11: Any.Type = Metatype<B>.self   // B.Type.Type
let q12: Any.Type = Metatype<C>.self   // C.Type.Type
let q13: Any.Type = Metatype<D>.self   // D.Protocol.Type
let q14: Any.Type = Metatype<Any>.self // protocol<>.Protocol.Type

let q15: Metatype<D>.Type = Metatype<D>.self


// Everything is 8 byte
sizeofValue(q1)
sizeofValue(q2)
sizeofValue(q3)
sizeofValue(q4)
sizeofValue(q5)
sizeofValue(q6)
sizeofValue(q7)
sizeofValue(q8)
sizeofValue(q9)
sizeofValue(q0)

sizeofValue(q10)
sizeofValue(q11)
sizeofValue(q12)
sizeofValue(q13)
sizeofValue(q14)

sizeofValue(q15)


sizeofValue(metatypeA)

// 0 bytes
sizeofValue(metatypeB)
sizeofValue(metatypeC)
sizeofValue(metatypeD)
sizeofValue(metatypeAny)

// 8 bytes
sizeofValue(A.self)

// 0 bytes
sizeofValue(B.self)
sizeofValue(C.self)
sizeofValue(D.self)
sizeofValue(Any.self)

// 8 bytes
sizeofValue(metatypeA_)

// 0 bytes
sizeofValue(metatypeB_)
sizeofValue(metatypeC_)
sizeofValue(metatypeD_)
sizeofValue(metatypeAny_)

// 8 bytes
sizeofValue(A.Type.self)

// 0 bytes
sizeofValue(B.Type.self)
sizeofValue(C.Type.self)
sizeofValue(D.Type.self)
sizeofValue(Any.Type.self)

// 8 bytes
sizeofValue(Metatype<A>.self)

// 0 bytes
sizeofValue(Metatype<B>.self)
sizeofValue(Metatype<C>.self)
sizeofValue(Metatype<D>.self)
sizeofValue(Metatype<Any>.self)
And also something like this (You can find the full experiment Gist here: LINK):

protocol P {}
protocol R : P {}
class A : P {}
class B : A, R {}

P.self is Any.Type                          //=> always true

// STRANGE ISSUE: does not require `.Type`
Mirror(P.self).is(Any.self)                 //=> true
Mirror(P.self).is(Type<Any>())              //=> true
Mirror(P.self).is(Type<Any>.metatype)       //=> true

P.self is Any.Protocol                      //=> false

Mirror(P.self).is(Any.Type.self)            //=> true
Mirror(P.self).is(Type<Any.Type>())         //=> true
Mirror(P.self).is(Type<Any.Type>.metatype)  //=> true

P.self is P.Type                            //=> true

Mirror(P.self).is(P.self)                   //=> true
Mirror(P.self).is(Type<P>())                //=> true
Mirror(P.self).is(Type<P>.metatype)         //=> true

R.self is Any.Type                          //=> always true

// STRANGE ISSUE: does not require `.Type`
Mirror(R.self).is(Any.self)                 //=> true
Mirror(R.self).is(Type<Any>())              //=> true
Mirror(R.self).is(Type<Any>().metatype)     //=> true

// KNOWN ISSUE: Without `.Type` we'd have `.Protocol`
// result -> FALSE
Mirror(R.self).is(Any.Type.self)            //=> true
Mirror(R.self).is(Type<Any.Type>())         //=> true
Mirror(R.self).is(Type<Any.Type>.metatype)  //=> true

// KNOWN ISSUE: I couldn't implemt it so it does
// work as expected
R.self is P.Type                            //=> true

Mirror(R.self).is(P.self)                   //=> false
Mirror(R.self).is(Type<P>())                //=> false
Mirror(R.self).is(Type<P>.metatype)         //=> false

// KNOWN ISSUE: mirror a protocol and check  
// against another protocol with `.Type` fails
Mirror(R.self).is(P.Type.self)              //=> false
Mirror(R.self).is(Type<P.Type>())           //=> false
Mirror(R.self).is(Type<P.Type>.metatype)    //=> false

R.self is R.Type                            //=> true

// STRANGE ISSUE: does not require `.Type`
Mirror(R.self).is(R.self)                   //=> true
Mirror(R.self).is(Type<R>())                //=> true
Mirror(R.self).is(Type<R>.metatype)         //=> true

// KNOWN ISSUE: mirror a protocol and check
// against another protocol with `.Type` fails
Mirror(R.self).is(R.Type.self)              //=> false
Mirror(R.self).is(Type<R.Type>())           //=> false
Mirror(R.self).is(Type<R.Type>.metatype)    //=> false

A.self is Any.Type                          //=> always true

// STRANGE ISSUE: does not require `.Type`
Mirror(A.self).is(Any.self)                 //=> true
Mirror(A.self).is(Type<Any>())              //=> true
Mirror(A.self).is(Type<Any>.metatype)       //=> true

// KNOWN ISSUE: Without `.Type` we'd have `.Protocol`
// result -> FALSE
Mirror(A.self).is(Any.Type.self)            //=> true
Mirror(A.self).is(Type<Any.Type>())         //=> true
Mirror(A.self).is(Type<Any.Type>.metatype)  //=> true

A.self is P.Type                            //=> always true

// KNOWN ISSUE: Without `.Type` we'd have `.Protocol`
// result -> FALSE
Mirror(A.self).is(P.Type.self)              //=> true
Mirror(A.self).is(Type<P.Type>())           //=> true
Mirror(A.self).is(Type<P.Type>.metatype)    //=> true

B.self is Any.Type                          //=> always true

// STRANGE ISSUE: does not require `.Type`
Mirror(B.self).is(Any.self)                 //=> true
Mirror(B.self).is(Type<Any>())              //=> true
Mirror(B.self).is(Type<Any>.metatype)       //=> true

// KNOWN ISSUE: Without `.Type` we'd have `.Protocol`
// result -> FALSE
Mirror(B.self).is(Any.Type.self)            //=> true
Mirror(B.self).is(Type<Any.Type>())         //=> true
Mirror(B.self).is(Type<Any.Type>.metatype)  //=> true

B.self is P.Type                            //=> always true

// KNOWN ISSUE: Without `.Type` we'd have `.Protocol`
// result -> FALSE
Mirror(B.self).is(P.Type.self)              //=> true
Mirror(B.self).is(Type<P.Type>())           //=> true
Mirror(B.self).is(Type<P.Type>.metatype)    //=> true

B.self is R.Type                            //=> always true

// KNOWN ISSUE: Without `.Type` we'd have `.Protocol`
// result -> FALSE
Mirror(B.self).is(R.Type.self)              //=> true
Mirror(B.self).is(Type<R.Type>())           //=> true
Mirror(B.self).is(Type<R.Type>.metatype)    //=> true

B.self is A.Type                            //=> always true

Mirror(B.self).is(A.self)                   //=> true
Mirror(B.self).is(Type<A>())                //=> true
Mirror(B.self).is(Type<A>.metatype)         //=> true


-- 
Adrian Zubarev
Sent with Airmail

Am 20. Juli 2016 um 04:30:38, Karl (razielim at gmail.com) schrieb:

In general a strong +1 because I’ve been bumping against the .Protocol problem several times.

I’m not sure about the name “Metatype” and the relationship with “Type” - particularly with the protocol example, it isn’t obvious to a novice user why it’s like this or what these mean.

You say that you want this for Swift 3, and it seems like you’ve done quite a lot of research in to the implementation details. When you talk about “internal” metatypes, do you mean that this information already exists, and that the majority of the implementation work would be to expose it?

Karl
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160720/be46936d/attachment.html>


More information about the swift-evolution mailing list