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
