[swift-evolution] [Discussion] Seal `T.Type` into `Type<T>`

Anton Zhilin antonyzhilin at gmail.com
Wed Jul 13 15:57:38 CDT 2016


An even better explanation of my suggestion: instead of *sealing* T.Type, I
suggest to *rename* it to Type<T>, formally turning it into a struct, and
then add size and align properties to it.
And regardless of how you interpret it, I suggest to remove .Type notation.

> In Swift, only class instances and metatypes have unique identities.
There is no notion of identity for structs, enums, functions, or tuples.
So Type<T> will lose identity. That's fine. They will contain unique
integer identifiers (assigned to types during compilation) to do its work.

> There is no special compiler magic needed
Maybe. At least, this behaviour will be needed in construction from type
literals:

func foo(_ x: Type<BaseClass>)
foo(DerivedClass)  // ok
foo(Int)           // compilation error

With Type<T>, I can see reflection coming! For example, Type<T> can have
the following property (although we shouldn't right now):

var fields: [String: (Type<Any>, (T) -> Any)] { get }

I suggest you to prepare a formal proposal, or I will try tomorrow. I would
take the direction on removal of T.Type notation.

2016-07-13 22:48 GMT+03:00 Adrian Zubarev via swift-evolution <
swift-evolution at swift.org>:

> Okay I get it now. You meant the size for a metatype sizeof(T.Type.self).
> This is indeed 8 bytes, at least not for optimized Bool (as you showed).
>
> Internally, Type contains an Int, i.e. identifier of a type. For every
> type, compiler must choose a different identifier
>
> We can already implement this with Hashable protocol.
>
> ObjectIdentifier: A unique identifier for a class instance or metatype.
>
> In Swift, only class instances and metatypes have unique identities. There
> is no notion of identity for structs, enums, functions, or tuples.
>
> // version 1:
> public let hashValue: Int = ObjectIdentifier(T.self).hashValue
>
> // version 2 (uses ObjectIdentifier calculation without
> // constructing an instance of ObjectIdentifier):
>
> init() {
>     // calculate the hashValue only once
>     // I'd rename `.self` to `.metatype`
>
>     let rawPointerMetatype = unsafeBitCast(T.self, to: Builtin.RawPointer.self)
>     self.hashValue = Int(Builtin.ptrtoint_Word(rawPointerMetatype))
> }
>
> public let hashValue: Int
>
> API of Type is defined so that it can only contain identifiers of
> subtypes of T
>
> For example, when you get a variable of Type, it can correspond to
> BaseClass or DerivedClass
>
> I did a quick test and I feel like this falls under the part of tweaking
> dynamic casts to work with Type<T>. There is no special compiler magic
> needed, unsafeBitCast should do the trick. Or we should teach dynamic
> casts to work with the inner type T instead of the whole Type<T>.
>
> public struct Type<T> : Hashable {
>
>     public let metatype: T.Type = T.self
>
>     public let hashValue: Int = ObjectIdentifier(T.self).hashValue
> }
>
> public func ==<T, U>(lhs: Type<T>, rhs: Type<U>) -> Bool {
>
>     return lhs.hashValue == rhs.hashValue
> }
>
> public func asOptionalCast<U, T>(type: Type<T>) -> Type<U>? {
>
>     guard (type.metatype as? U.Type) != nil else {
>         return nil
>     }
>     return unsafeBitCast(type, to: Type<U>.self)
> }
>
> class A {}
> class B: A {}
>
> let typeB = Type<B>()
>
> // downcast Type<B> to Type<A>
> let downcast: Type<A>? = asOptionalCast(type: typeB)
>
> (downcast! == typeB) == true
>
> // cast Type<A> (which here is Type<B>) back to Type<B>
> let upcast: Type<B>? = asOptionalCast(type: downcast!)
>
> (upcast! == Type<B>()) == true
>
> The good part here that the hash value of the casted type won’t change and
> testing against a new instance of the same dynamic type will be always true.
>
>
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> Am 13. Juli 2016 um 20:31:22, Anton Zhilin (antonyzhilin at gmail.com)
> schrieb:
>
> 2016-07-13 20:19 GMT+03:00 Adrian Zubarev via swift-evolution <
> swift-evolution at swift.org>:
>>
>> Am 13. Juli 2016 um 18:30:53, Anton Zhilin (antonyzhilin at gmail.com)
>> schrieb:
>>
>> I see model of Type<T> as follows:
>>
>>    1. Values of Type<T> are identifiers of types (8 bytes, I guess)
>>    2. All used identifiers are contained in Type<Any>
>>    3. Type<T> contains a subset of those identifiers
>>
>> I can’t follow your though here. Is this a totally new behavior?
>>
> That's how it works right now:
>
> sizeofValue(Bool.self)              //=> 0 (optimized away)
> sizeofValue(Bool.self as Any.self)  //=> 8
>
> I'll put my thoughts another way:
>
>    - Internally, Type<T> contains an Int, i.e. identifer of a type. For
>    every type, compiler must choose a different identifier
>    - API of Type<T> is defined so that it can only contain identifiers of
>    subtypes of T
>    - For example, when you get a variable of Type<BaseClass>, it can
>    correspond to BaseClass or DerivedClass
>
>
>>    1. Upcasting uses constructor init<U: T>(upcasting: Type<U>)
>>
>> It does look neat but I can’t implement it. At least I have no clue how
>> to solve the problem that `T` is not a protocol or a class type.
>>
> We should add implicit convertion of Type<U> to Type<T>, dulicating
> current behaviour of `as T.Type`.
> That constructor still can be useful, but it will be failable and not that
> significant in practise.
> I don't like adding compiler magic, but I guess we really should in this
> case, because otherwise Type<T> can't replace T.Type.
>
>>
>>    1. Size of Type<Type<T>> is 8, static size of Type<SomeProtocol> is 0
>>
>> I feel like you mean something different here than this:
>>
>> ```swift
>>
>> protocol SomeProtocol {}
>>
>>
>> sizeof(SomeProtocol.self) == 40
>>
>> ```
>>
>
> That was a mistake. Static size of Type<SomeProtocol> will be 40, and
> size property of its values can be less or greater than 40, depending on
> internal type identifier.
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160713/5fc5f7a8/attachment.html>


More information about the swift-evolution mailing list