<html><head><style>
body {
        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
        padding:1em;
        margin:auto;
        background:#fefefe;
}
h1, h2, h3, h4, h5, h6 {
        font-weight: bold;
}
h1 {
        color: #000000;
        font-size: 28pt;
}
h2 {
        border-bottom: 1px solid #CCCCCC;
        color: #000000;
        font-size: 24px;
}
h3 {
        font-size: 18px;
}
h4 {
        font-size: 16px;
}
h5 {
        font-size: 14px;
}
h6 {
        color: #777777;
        background-color: inherit;
        font-size: 14px;
}
hr {
        height: 0.2em;
        border: 0;
        color: #CCCCCC;
        background-color: #CCCCCC;
display: inherit;
}
p, blockquote, ul, ol, dl, li, table, pre {
        margin: 15px 0;
}
a, a:visited {
        color: #4183C4;
        background-color: inherit;
        text-decoration: none;
}
#message {
        border-radius: 6px;
        border: 1px solid #ccc;
        display:block;
        width:100%;
        height:60px;
        margin:6px 0px;
}
button, #ws {
        font-size: 12 pt;
        padding: 4px 6px;
        border-radius: 5px;
        border: 1px solid #bbb;
        background-color: #eee;
}
code, pre, #ws, #message {
        font-family: Monaco;
        font-size: 10pt;
        border-radius: 3px;
        background-color: #F8F8F8;
        color: inherit;
}
code {
        border: 1px solid #EAEAEA;
        margin: 0 2px;
        padding: 0 5px;
}
pre {
        border: 1px solid #CCCCCC;
        overflow: auto;
        padding: 4px 8px;
}
pre > code {
        border: 0;
        margin: 0;
        padding: 0;
}
#ws { background-color: #f8f8f8; }
.bloop_markdown table {
border-collapse: collapse;
font-family: Helvetica, arial, freesans, clean, sans-serif;
color: rgb(51, 51, 51);
font-size: 15px; line-height: 25px;
padding: 0; }
.bloop_markdown table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
.bloop_markdown table tr:nth-child(2n) {
background-color: #f8f8f8; }
.bloop_markdown table tr th {
font-weight: bold;
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
.bloop_markdown table tr td {
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
.bloop_markdown table tr th :first-child, table tr td :first-child {
margin-top: 0; }
.bloop_markdown table tr th :last-child, table tr td :last-child {
margin-bottom: 0; }
.bloop_markdown blockquote{
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777; }
blockquote > :first-child {
margin-top: 0; }
blockquote > :last-child {
margin-bottom: 0; }
code, pre, #ws, #message {
word-break: normal;
word-wrap: normal;
}
hr {
display: inherit;
}
.bloop_markdown :first-child {
-webkit-margin-before: 0;
}
code, pre, #ws, #message {
font-family: Menlo, Consolas, Liberation Mono, Courier, monospace;
}
.send { color:#77bb77; }
.server { color:#7799bb; }
.error { color:#AA0000; }</style></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="bloop_markdown"><p>I still can’t get my head around this.</p>
<p>Originally I wanted to seal <code>T.Type</code> completely but I realized that there are to many downsides, therefore I think it’s better to revise the way how we construct a metatype in Swift + how to solve the ambiguity in array/dictionary shorthand syntax + open the door for reflections + combining SE–0101 into <code>Type<T></code>.</p>
<p>I don’t think we have to make the whole model of <code>Type<T></code> that complicated that it contains different identifier for each type. This is already solved with metatypes.</p>
<p>The thing I believe you misinterpret with <code>Type<T></code> being the same as <code>T.Type</code> is that if <code>Type<T></code> would act like <code>T.Type</code>:</p>
<pre><code class="swift">T.self.init == T.init
T.self.staticMember == T.staticMember
</code></pre>
<p>We won’t be able to extend <code>Type<T></code> at all because otherwise all static members of <code>Type<T></code> would be reserved and cannot be implemented in <code>T</code>, which is clearly not how it should work.</p>
<pre><code class="swift">Type<T>.init != T.init
Type<T>.staticMember != T.staticMember
</code></pre>
<p>Thats why I’m talking about the <code>metatype</code> property all the time.</p>
<p>Here is full bikeshedding implementation. I’ll use <code>T.Metatype</code> instead of <code>T.Type</code> for internal use only + <code>T.metatype</code> instead of <code>T.self</code> for internal use only + I’ll drop <code>.self</code> in public use and assume we can construct <code>Type<T></code> from <code>T</code>.</p>
<pre><code class="swift">/// `T.metatype` returns an instance of `T.Metatype` == `Metatype<T>`
/// `T.metatype` is only used internally and not visible in public
/// `T.Metatype` is visible in public but not allowed in declarations - use `Metatype<T>` instead
/// `T.self` is dropped in public
/// `T` returns an instance of `Type<T>` if its not part of a declaration
/// To instantiate `Metatype<T>` use `Type<T>.metatype` or `Type<T>().metatype`
internal func _sizeof<T>(_ metatype: Metatype<T>) -> Int {
return Int(Builtin.sizeof(metatype))
}
internal func _strideof<T>(_ metatype: Metatype<T>) -> Int {
return Int(Builtin.strideof_nonzero(metatype))
}
internal func _alignof<T>(_ metatype: Metatype<T>) -> Int {
return Int(Builtin.alignof(metatype))
}
public func unsafeBitCast<T, U>(_: T, to: Type<U>) -> U { ... }
public typealias Metatype<T> = T.Metatype
public struct Type<T> : Hashable, CustomStringConvertible, CustomDebugStringConvertible {
// Stored as `Any` to make `init?(casting:)` work as expected.
// There is no need to contain different identifier like a Set!
internal let _underlyingMetatype: Any
internal let _uniqueIdentifier: Int
public init() {
self._underlyingMetatype = T.metatype
// Same hash calculation like in `ObjectIdentifier`
let rawPointerMetatype = unsafeBitCast(T.metatype, to: Builtin.RawPointer.metatype)
self._uniqueIdentifier = Int(Builtin.ptrtoint_Word(rawPointerMetatype))
}
public init(_ copy: Type<T>) {
self._underlyingMetatype = copy._underlyingMetatype
self._uniqueIdentifier = copy._uniqueIdentifier
}
// Creates an instance referring to type, which is referred by `otherType`, if possible
public init?<U>(casting otherType: Type<U>) {
// check if we can up- or downcast ther metatype from `otherType` to `Metatype<T>`
guard (otherType._underlyingMetatype as? Metatype<T>) != nil else {
return nil
}
// create a new `Type<T>` but copy the metatype and the identifier from `otherType`
self._underlyingMetatype = otherType._underlyingMetatype
self._uniqueIdentifier = otherType._uniqueIdentifier
}
public func `is`<U>(_ otherType: Type<U>) -> Bool {
return Type<U>(casting: self) != nil
}
public var metatype: Metatype<T> { return Type<T>.metatype }
public static var metatype: Metatype<T> { return T.metatype }
// do not construct full `Type<T>` - use lightweight static calculation instead
public var size: Int { return Type<T>.size }
public var stride: Int { return Type<T>.stride }
public var alignment: Int { return Type<T>.alignment }
public static var size: Int { return _sizeof(Type<T>.metatype) }
public static var stride: Int { return _strideof(Type<T>.metatype) }
public static var alignment: Int { return _alignof(Type<T>.metatype) }
public var hashValue: Int { return self._uniqueIdentifier }
public var description: String {
return "Type<\(self.metatype)>"
}
public var debugDescription: String {
return "<" + self.description
+ " metatype: \(self.metatype)"
+ " size: \(self.size)"
+ " stride: \(self.stride)"
+ " alignment: \(self.alignment)>"
}
}
public func ==<T, U>(lhs: Type<T>, rhs: Type<U>) -> Bool {
return lhs.hashValue == rhs.hashValue
}
/// class A {}
/// class B: A {}
///
/// let anything: Any = B()
///
/// `Any.Type` or `Metatype<Any>`
/// let metatype = dynamicType(anything)
///
/// ((metatype as? Metatype<B>) != nil) == true
///
// This function can only extract the metatype from an instance.
// What we'll do to the metatype is up to us.
public func `dynamicType`<T>(_: T) -> Metatype<T> {
return Type<T>.metatype
}
</code></pre>
<p>And proof of concept:</p>
<pre><code class="swift">typealias Metatype<T> = T.Type
class A {}
class B: A {}
class C {}
let metatype: Any = B.self
((metatype as? Metatype<A>) != nil) == true
((metatype as? Metatype<B>) != nil) == true
((metatype as? Metatype<C>) != nil) == false
</code></pre>
<p></p></div><div class="bloop_original_html"><style>body{font-family:Helvetica,Arial;font-size:13px}</style><div id="bloop_customfont" style="font-family:Helvetica,Arial;font-size:13px; color: rgba(0,0,0,1.0); margin: 0px; line-height: auto;"><br></div> <br> <div id="bloop_sign_1468523677711859968" class="bloop_sign"><div style="font-family:helvetica,arial;font-size:13px">-- <br>Adrian Zubarev<br>Sent with Airmail</div></div> <br><p class="airmail_on">Am 14. Juli 2016 um 21:01:24, Anton Zhilin (<a href="mailto:antonyzhilin@gmail.com">antonyzhilin@gmail.com</a>) schrieb:</p> <blockquote type="cite" class="clean_bq"><span><div><div></div><div>
<title></title>
<div dir="ltr">I didn't send the link to evolution, so here it is:
<div><a href="https://gist.github.com/Anton3/08a069a3b6f634bece7ad666922741d2">https://gist.github.com/Anton3/08a069a3b6f634bece7ad666922741d2</a></div>
<div><br></div>
<div>Response inline:</div>
<div class="gmail_extra"><br>
<div class="gmail_quote">2016-07-14 20:52 GMT+03:00 Adrian Zubarev
via swift-evolution <span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>></span>:
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
<div style="word-wrap:break-word">
<div>
<ul>
<li>
<p>There is a small typo (SE–0090 is not accepted yet) - only in
the first example:</p>
<pre><code>func unsafeBitCast<T, U>(_: T, to: U.Type)
unsafeBitCast(10, to: Double)
// The second line should be
unsafeBitCast(10, to: Double.self)</code></pre></li>
</ul>
</div>
</div>
</blockquote>
<div>I'll fix the examples.</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
<div style="word-wrap:break-word">
<div>
<ul>
<li>
<blockquote>
<p>Size and internal structure of Type will be the same as of
T.Type</p>
</blockquote>
<ul>
<li>Do we really need this to be the same?</li>
</ul>
</li>
</ul>
</div>
</div>
</blockquote>
<div>Yes, otherwise we cannot remove <font face="monospace, monospace">T.Type</font>. If you want to store
<i>additional</i> data in <font face="monospace, monospace">Type<T></font> and have a reason for
that, then why not.</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
<div style="word-wrap:break-word">
<div>
<ul>
<li>
<blockquote>
<p>Values of Type store identifiers of U such that U: T.</p>
</blockquote>
<ul>
<li>Why would we want to store more than one unique
identifier?</li>
</ul>
</li>
</ul>
</div>
</div>
</blockquote>
<div>Another try at explaining my model of <font face="monospace, monospace">Type<T></font>. Warning: it will be a
long read this time!</div>
<div><br></div>
<div>During compilation, each type is assigned a unique integer
identifier. Let's suppose there are only three types used in the
program: <font face="monospace, monospace">Any</font> is 1,
<font face="monospace, monospace">BaseClass</font> is 2,
<font face="monospace, monospace">DerivedClass</font> is 3.</div>
<div><br></div>
<div>Values of type <font face="monospace, monospace">Type<Any></font> can contain one of
identifiers 1, 2 or 3.</div>
<div>Values of type <font face="monospace, monospace">Type<BaseClass></font> can contain one
of identifiers 2 or 3.</div>
<div>Values of type <font face="monospace, monospace">Type<DerivedClass></font> can only
contain 3.</div>
<div><br></div>
<div>The same in terms of sets:<br></div>
<div><br></div>
<div><font face="monospace, monospace">Type<Any> = { 1, 2, 3
}</font></div>
<div><font face="monospace, monospace">Type<BaseClass> = { 2,
3 }</font></div>
<div><font face="monospace, monospace">Type<DerivedClass> = {
3 }</font></div>
<div><br></div>
<div>In terms of set theory, type <font face="monospace, monospace">Type<T></font> contains identifiers of
all types <font face="monospace, monospace">U</font> that are
subtypes of <font face="monospace, monospace">T</font>.</div>
<div>If <font face="monospace, monospace">U1</font>, ..., Uk
are subtypes of <font face="monospace, monospace">T</font> used in
the program, then <font face="monospace, monospace">Type<T></font> = { T, U1, ..., Uk
}</div>
<div><br></div>
<div>Example:</div>
<div><br></div>
<div><font face="monospace, monospace">let x =
Type<MyType>()</font></div>
<font face="monospace, monospace">let y =
Type<MyProtocol>(casting: x)<br>
Type<MyType>.size //=> 50<br>
Type<MyProtocol>.size //=> 40</font>
<div><font face="monospace, monospace">x.size
//=> 50</font></div>
<div><font face="monospace, monospace">y.size
//=> 50</font></div>
<div><br></div>
<div>Again, example with <font face="monospace, monospace">dynamicType</font>. Let's suppose that
<font face="monospace, monospace">T = BaseClass</font> and
<font face="monospace, monospace">DerivedClass:
BaseClass</font>.</div>
<div><br></div>
<div><font face="monospace, monospace">func dynamicType(_ value:
BaseClass) -> Type<BaseClass></font></div>
<div><br></div>
<div>We can't know statically, which type information it
returns.</div>
<div><font face="monospace, monospace">Type<BaseClass> = { 2,
3 }</font></div>
<div>At runtime, we get to know if <font face="monospace, monospace">value</font> is of <font face="monospace, monospace">BaseClass</font> or of <font face="monospace, monospace">DerivedClass</font>.</div>
<div><br></div>
<div>In my version, <font face="monospace, monospace">Type<T></font> should get all
capabilities and all syntax of <font face="monospace, monospace">T.Type</font>, therefore we should be able
to drop the latter.</div>
<div><br></div>
<div>Again, main idea: <b>rename</b> <font face="monospace, monospace">T.Type</font> to <font face="monospace, monospace">Type<T></font><font face="arial, helvetica, sans-serif">, <b>maintain</b> its behaviour and
tweak syntax</font>.</div>
<div><br></div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
<div style="word-wrap:break-word">
<div>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.<br>
<pre><code>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
</code></pre>
<p>I wouldn’t want to throw this away.</p>
</div>
</div>
</blockquote>
<div>We won't lose literally anything by moving from <font face="monospace, monospace">T.Type</font> to <font face="monospace, monospace">Type<T></font>.</div>
<div><br></div>
<div><font face="monospace, monospace">of</font>
returns <font face="monospace, monospace">MemoryLayout<T>.Type</font>, which
currently doesn't have <font face="monospace, monospace">size</font> property. Could you correct your
example?</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
<div style="word-wrap:break-word">
<div>
<p>I played with the idea of keeping <code>T.Type</code> internally
but disallow it in public declarations. Furthermore metatypes would
still exist, but can only be instantiated through
<code>Type<T>.metatype</code> or
<code>Type<T>().metatype</code>.</p>
<p>To keep the neat designing feature but get rid of
<code>T.Type</code> we could abuse generic typealiases here:</p>
<pre><code>// 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 }
…
}
</code></pre>
<p>That way the sample from above won’t break from its designing
point, but will require some refactoring:</p>
<pre><code>extension MemoryLayout<T> {
init(_ : @autoclosure () -> T) {}
public static func of(_ candidate : @autoclosure () -> T) -> Metatype<MemoryLayout<T>> {
return dynamicType(MemoryLayout.init(candidate)).metatype
}
}</code></pre></div>
</div>
</blockquote>
<div> If you wish, <font face="monospace, monospace">Type<T></font> in my version is
rebranded metatype <font face="monospace, monospace">T.Type</font>.</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
<div style="word-wrap:break-word">
<div>
<pre><span style="font-family:arial,sans-serif">We should also mention that dynamic casts need some tweaking to work with </span><code>Type<T></code><span style="font-family:arial,sans-serif">.</span></pre></div>
</div>
</blockquote>
<div>In the gist, I suggest to live without tweaking and replace
dynamic casts with failable initializer of <font face="monospace, monospace">Type<T></font>. That will tweaking
syntax of that casts, but reduce amount of magic.</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
<div style="word-wrap:break-word">
<div>
<pre><span style="font-family:arial,sans-serif">And one more thing:</span><br></pre>
<pre><code>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 }
</code></pre>
<p>Shouldn’t these work exactly the opposite way? If in the future
<code>Type<T></code> would be extended with reflection
functionality and contain more stored properties, it would be
lightweight to compute <code>size</code> etc. from static
<code>size</code> without the need of instantiating the whole
type.</p>
</div>
</div>
</blockquote>
<div>See example above with sizes.</div>
</div>
</div>
</div>
</div></div></span></blockquote></div><div class="bloop_markdown"><p></p></div></body></html>