I still didn't answer the original question: >> Values of Type store identifiers of U such that U: T. >Why would we want to store more than one unique identifier?
We don't. What I meant is the following. Type<T> can have multiple non-equal values. Each of them contains a single identifier of some type U:T. This type U is different for non-equal values of Type<T>. 2016-07-14 22:01 GMT+03:00 Anton Zhilin <[email protected]>: > I didn't send the link to evolution, so here it is: > https://gist.github.com/Anton3/08a069a3b6f634bece7ad666922741d2 > > Response inline: > > 2016-07-14 20:52 GMT+03:00 Adrian Zubarev via swift-evolution < > [email protected]>: >> >> >> - >> >> There is a small typo (SE–0090 is not accepted yet) - only in the >> first example: >> >> func unsafeBitCast<T, U>(_: T, to: U.Type) >> unsafeBitCast(10, to: Double) >> >> // The second line should be >> unsafeBitCast(10, to: Double.self) >> >> >> I'll fix the examples. > >> >> - >> >> Size and internal structure of Type will be the same as of T.Type >> >> - Do we really need this to be the same? >> >> Yes, otherwise we cannot remove T.Type. If you want to store *additional* > data in Type<T> and have a reason for that, then why not. > >> >> - >> - >> >> Values of Type store identifiers of U such that U: T. >> >> - Why would we want to store more than one unique identifier? >> >> Another try at explaining my model of Type<T>. Warning: it will be a > long read this time! > > During compilation, each type is assigned a unique integer identifier. > Let's suppose there are only three types used in the program: Any is 1, > BaseClass is 2, DerivedClass is 3. > > Values of type Type<Any> can contain one of identifiers 1, 2 or 3. > Values of type Type<BaseClass> can contain one of identifiers 2 or 3. > Values of type Type<DerivedClass> can only contain 3. > > The same in terms of sets: > > Type<Any> = { 1, 2, 3 } > Type<BaseClass> = { 2, 3 } > Type<DerivedClass> = { 3 } > > In terms of set theory, type Type<T> contains identifiers of all types U > that are subtypes of T. > If U1, ..., Uk are subtypes of T used in the program, then Type<T> = { T, > U1, ..., Uk } > > Example: > > let x = Type<MyType>() > let y = Type<MyProtocol>(casting: x) > Type<MyType>.size //=> 50 > Type<MyProtocol>.size //=> 40 > x.size //=> 50 > y.size //=> 50 > > Again, example with dynamicType. Let's suppose that T = BaseClass and > DerivedClass: > BaseClass. > > func dynamicType(_ value: BaseClass) -> Type<BaseClass> > > We can't know statically, which type information it returns. > Type<BaseClass> = { 2, 3 } > At runtime, we get to know if value is of BaseClass or of DerivedClass. > > In my version, Type<T> should get all capabilities and all syntax of > T.Type, therefore we should be able to drop the latter. > > Again, main idea: *rename* T.Type to Type<T>, *maintain* its behaviour > and tweak syntax. > > Actually I thought for a while about the negative effect of fully removing >> metatypes from the language. Metatypes allow us to build neat looking >> execution branches like showed in SE–0101. >> >> extension MemoryLayout<T> { >> init(_ : @autoclosure () -> T) {} >> public static func of(_ candidate : @autoclosure () -> T) -> >> MemoryLayout<T>.Type { >> return MemoryLayout.init(candidate).dynamicType >> } >> } >> >> // Value >> let x: UInt8 = 5 >> MemoryLayout.of(x).size // 1 >> MemoryLayout.of(1).size // 8 >> MemoryLayout.of("hello").stride // 24 >> MemoryLayout.of(29.2).alignment // 8 >> >> I wouldn’t want to throw this away. >> > We won't lose literally anything by moving from T.Type to Type<T>. > > of returns MemoryLayout<T>.Type, which currently doesn't have size > property. Could you correct your example? > >> I played with the idea of keeping T.Type internally but disallow it in >> public declarations. Furthermore metatypes would still exist, but can only >> be instantiated through Type<T>.metatype or Type<T>().metatype. >> >> To keep the neat designing feature but get rid of T.Type we could abuse >> generic typealiases here: >> >> // T.Type would be only visible here but is disallowed in public declarations >> // in favor of `Metatype<T>` >> public typealias Metatype<T> = T.Type >> >> public struct Type<T> : Hashable, CustomStringConvertible, >> CustomDebugStringConvertible { >> >> … >> public var metatype: Metatype<T> { return Type<T>.metatype } >> >> // Internally `.self` should be renamed to `.metatype` and return >> // a metatype instance >> public static var metatype: Metatype<T> { return T.metatype } >> … >> } >> >> That way the sample from above won’t break from its designing point, but >> will require some refactoring: >> >> extension MemoryLayout<T> { >> init(_ : @autoclosure () -> T) {} >> public static func of(_ candidate : @autoclosure () -> T) -> >> Metatype<MemoryLayout<T>> { >> return dynamicType(MemoryLayout.init(candidate)).metatype >> } >> } >> >> If you wish, Type<T> in my version is rebranded metatype T.Type. > >> We should also mention that dynamic casts need some tweaking to work with >> Type<T>. >> >> In the gist, I suggest to live without tweaking and replace dynamic casts > with failable initializer of Type<T>. That will tweaking syntax of that > casts, but reduce amount of magic. > >> And one more thing: >> >> public var size: Int { get } >> public var stride: Int { get } >> public var alignment: Int { get } >> >> public static var size: Int { return Type<T>().size } >> public static var stride: Int { return Type<T>().stride } >> public static var alignment: Int { return Type<T>().alignment } >> >> Shouldn’t these work exactly the opposite way? If in the future Type<T> >> would be extended with reflection functionality and contain more stored >> properties, it would be lightweight to compute size etc. from static size >> without the need of instantiating the whole type. >> > See example above with sizes. >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
