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 ([email protected]) schrieb:

2016-07-13 20:19 GMT+03:00 Adrian Zubarev via swift-evolution 
<[email protected]>:
Am 13. Juli 2016 um 18:30:53, Anton Zhilin ([email protected]) schrieb:

I see model of Type<T> as follows:
Values of Type<T> are identifiers of types (8 bytes, I guess)
All used identifiers are contained in Type<Any>
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
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.
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
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to