[swift-evolution] [Pitch] Refactor Metatypes

Anton Zhilin antonyzhilin at gmail.com
Fri Sep 30 16:05:54 CDT 2016


2016-09-30 22:48 GMT+03:00 Xiaodi Wu via swift-evolution <
swift-evolution at swift.org>:

Sorry, my question at least has nothing to do with bikeshedding. I'm
> confused about why the proposal feels it's necessary to have both Type and
> Subtype. I don't understand Brent's two reasons and was hoping for some
> elaboration. I've tried to clarify my question in a gist:
>
> https://gist.github.com/xwu/0cc2c8d358f1fdf066ba739bcd151167
>
Regardless of syntax, there are Metatype<T> and ExistentialMetatype<T>
“under the hood”. I’ll take the liberty to use these names for this post.

Purpose and difference between the two kinds of metatypes is easy to
understand. If it helps, size of Metatype<T> is typically 0 while size of
ExistentialMetatype<T> is typically 8.

NOTE: Metatype<P> can’t be a subtype of ExistentialMetatype<P> for
protocols P, because protocols do not implement their own static
requirements.

Apparently, creators of Swift also thought that two kinds of metatypes are
too difficult for an average developer. So an attempt was made to unify
both under a single name, T.Type. For “final” types like structs, T.Type
maps onto Metatype<T>. For classes and protocols, T.Type maps onto
ExistentialMetatype<T>.

This abstraction turned out to be leaky. I’ll give 3 leaks.

   1. Because of Note, we could not have ID of a protocol itself inside of
   any kind of metatype. This feature was needed in real code. The solution
   was to add T.Protocol syntax that could only be used for protocols to
   create a Metatype<T>. But this solution created a plethora of other
   inconsistencies and abstraction leaks (which were explored by Adrian).
   Arguably the most important is (2).
   2. In generic functions accepting T.Type, passing T.self creates an
   instance of T.Protocol, which is still described in code as T.Type.
   *boom!*
   3. Accepting static metatypes in functions is often what people want.
   Consider the following basic example:

func create<T: Creatable>(type: T.Type)

Most probably, create does not read contents of type to deal with
appropriate subtype. It does not support existentiality, type is here for
function specialization. But in case T is subtypable, we still pass around
those 8 bytes that are not used by the create, confusing both compiler and
some developers. In 90% cases, when we see such a function, it throws off
value of metatype instance.
​
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161001/388fabdb/attachment.html>


More information about the swift-evolution mailing list