[Review] SE-0126: Refactor Metatypes, repurpose T.self and Mirror


(Chris Lattner) #1

Hello Swift community,

The review of "SE-0126: Refactor Metatypes, repurpose T.self and Mirror" begins now and runs through July 24. The proposal is available here:

  https://github.com/apple/swift-evolution/blob/master/proposals/0126-refactor-metatypes-repurpose-t-dot-self-and-mirror.md

Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

  https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the review manager.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and contribute to the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  * What is your evaluation of the proposal?
  * Is the problem being addressed significant enough to warrant a change to Swift?
  * Does this proposal fit well with the feel and direction of Swift?
  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at

  https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Chris Lattner
Review Manager


(Brent Royal-Gordon) #2

  * What is your evaluation of the proposal?

I think this proposal is a huge mess. I don't understand why the split between `Type` and `Metatype` exists. I think `Mirror` seems half-baked; it ought to be omitted entirely until we can actually design a reflection system.

And *I can't even tell if these are actual problems*. It's possible that the design is just fine, but the proposal explains it poorly. At minimum, the proposal should be rewritten and the type names reconsidered. I'm not a person who gets confused by metatypes, but I simply cannot make heads or tails of this proposal.

My general sense of this area is that the main problem is the dual meaning of T.Type. T.Type wants to simultaneously be the type of the type instance and the supertype of all subtype type instances. But this breaks down with protocols, because protocol existentials don't conform to themselves. So we end up with `T.Protocol`, which gets confusingly renamed when it crosses generic boundaries.

I think the answer here is to split these two roles:

1. `Metatype<T>` is the type of the type instance. `T.self` is of type `Metatype<T>`. (Yes, we can call it `T.metatype` if we want.) Subtype-supertype relationships don't translate directly to metaclasses; `Metatype<Subclass>` is not a subtype of `Metatype<Superclass>`.

2. `T.Subtype` (or `T.SubtypeMetatype`? `T.Conforming`? this needs bikeshedding) is the supertype of all metatypes for `T` and its subtypes. `T.Subtype` is sort of like a protocol, in that there are no concrete instances of it, so it makes no sense to instantiate it. For classes, it only includes required (i.e. inherited) initializers.

Happily, I believe—though I may be wrong—that we can mostly resyntax to fix this immediate problem. Adding new capabilities, like extending the metatypes of specific types and adding universal members, can wait (or mostly wait) for another day.

(But in general, I would like to see those added directly on `Metatype`, and I would like extending `Metatype<T>` with instance members to be equivalent to extending `T` with static/class members. I'd also like to conform metatypes to protocols, to somehow define `Metatype` in the standard library as a relatively ordinary Swift type, and to have a pony.)

  * Is the problem being addressed significant enough to warrant a change to Swift?

Yes.

  * Does this proposal fit well with the feel and direction of Swift?

I have no idea, because I can't understand the proposal.

  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Most metatype (well, metaclass) systems I've worked with have been in more dynamic, runtime-oriented languages like Objective-C and Ruby.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I've been following the threads since the beginning. (And I still don't understand the proposal.) I haven't been able to articulate my objections; honestly, I still can't, but I've run out of time to wait and see if I can figure things out.

···

On Jul 20, 2016, at 5:18 PM, Chris Lattner <clattner@apple.com> wrote:

--
Brent Royal-Gordon
Architechies


(Joe Groff) #3

Before passing judgment on any particular ideas, I want to say that this proposal is huge, and I see no realistic way we can evaluate and implement this in the remaining week for source-breaking changes to Swift 3. I would recommend:

- Breaking it up into smaller proposals. There are quite a few orthogonal points that deserve independent evaluation, including:
  - Renaming T.Type and T.Protocol to Type<T>, or something similar
  - Splitting the responsibility of metatypes into two separate concepts
  - Folding MemoryLayout into one of those concepts
  - Renaming Mirror

- Since it's unlikely we can take this for Swift 3, sketching out a migration plan to bring the functionality to a future version of Swift. We will need a deprecation period where both the old and new functionality are supported. We will also need to ensure the implementation and runtime can remain compatible with deployed binaries using the Swift 3 behavior.

The latter point should probably be a requirement for all proposals going forward.

-Joe

···

On Jul 20, 2016, at 5:18 PM, Chris Lattner <clattner@apple.com> wrote:

Hello Swift community,

The review of "SE-0126: Refactor Metatypes, repurpose T.self and Mirror" begins now and runs through July 24. The proposal is available here:

  https://github.com/apple/swift-evolution/blob/master/proposals/0126-refactor-metatypes-repurpose-t-dot-self-and-mirror.md

Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

  https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the review manager.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and contribute to the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  * What is your evaluation of the proposal?
  * Is the problem being addressed significant enough to warrant a change to Swift?
  * Does this proposal fit well with the feel and direction of Swift?
  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at

  https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Chris Lattner
Review Manager

_______________________________________________
swift-evolution-announce mailing list
swift-evolution-announce@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution-announce


(Chris Lattner) #4

As mentioned on another thread, this proposal has been withdrawn. Thanks,

-Chris

···

On Jul 20, 2016, at 5:18 PM, Chris Lattner <clattner@apple.com> wrote:

Hello Swift community,

The review of "SE-0126: Refactor Metatypes, repurpose T.self and Mirror" begins now and runs through July 24. The proposal is available here:

  https://github.com/apple/swift-evolution/blob/master/proposals/0126-refactor-metatypes-repurpose-t-dot-self-and-mirror.md


(John McCall) #5

  * What is your evaluation of the proposal?

I think this proposal is a huge mess. I don't understand why the split between `Type` and `Metatype` exists. I think `Mirror` seems half-baked; it ought to be omitted entirely until we can actually design a reflection system.

And *I can't even tell if these are actual problems*. It's possible that the design is just fine, but the proposal explains it poorly. At minimum, the proposal should be rewritten and the type names reconsidered. I'm not a person who gets confused by metatypes, but I simply cannot make heads or tails of this proposal.

My general sense of this area is that the main problem is the dual meaning of T.Type. T.Type wants to simultaneously be the type of the type instance and the supertype of all subtype type instances.

It's not quite as general as that; it wants to be the supertype of subclass metatypes.

But this breaks down with protocols, because protocol existentials don't conform to themselves. So we end up with `T.Protocol`, which gets confusingly renamed when it crosses generic boundaries.

That's not why you need T.Protocol, but it's not that important here.

John.

···

On Jul 21, 2016, at 2:30 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

On Jul 20, 2016, at 5:18 PM, Chris Lattner <clattner@apple.com> wrote:

I think the answer here is to split these two roles:

1. `Metatype<T>` is the type of the type instance. `T.self` is of type `Metatype<T>`. (Yes, we can call it `T.metatype` if we want.) Subtype-supertype relationships don't translate directly to metaclasses; `Metatype<Subclass>` is not a subtype of `Metatype<Superclass>`.

2. `T.Subtype` (or `T.SubtypeMetatype`? `T.Conforming`? this needs bikeshedding) is the supertype of all metatypes for `T` and its subtypes. `T.Subtype` is sort of like a protocol, in that there are no concrete instances of it, so it makes no sense to instantiate it. For classes, it only includes required (i.e. inherited) initializers.

Happily, I believe—though I may be wrong—that we can mostly resyntax to fix this immediate problem. Adding new capabilities, like extending the metatypes of specific types and adding universal members, can wait (or mostly wait) for another day.

(But in general, I would like to see those added directly on `Metatype`, and I would like extending `Metatype<T>` with instance members to be equivalent to extending `T` with static/class members. I'd also like to conform metatypes to protocols, to somehow define `Metatype` in the standard library as a relatively ordinary Swift type, and to have a pony.)

  * Is the problem being addressed significant enough to warrant a change to Swift?

Yes.

  * Does this proposal fit well with the feel and direction of Swift?

I have no idea, because I can't understand the proposal.

  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Most metatype (well, metaclass) systems I've worked with have been in more dynamic, runtime-oriented languages like Objective-C and Ruby.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I've been following the threads since the beginning. (And I still don't understand the proposal.) I haven't been able to articulate my objections; honestly, I still can't, but I've run out of time to wait and see if I can figure things out.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(L Mihalkovic) #6

said as much privately (just not that colorfully though) to author, trying to hint at a number of problems that limited its usefulness.

Regards
LM
(From mobile)

···

On Jul 21, 2016, at 11:30 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

On Jul 20, 2016, at 5:18 PM, Chris Lattner <clattner@apple.com> wrote:

   * What is your evaluation of the proposal?

I think this proposal is a huge mess. I don't understand why the split between `Type` and `Metatype` exists. I think `Mirror` seems half-baked; it ought to be omitted entirely until we can actually design a reflection system.

And *I can't even tell if these are actual problems*. It's possible that the design is just fine, but the proposal explains it poorly. At minimum, the proposal should be rewritten and the type names reconsidered. I'm not a person who gets confused by metatypes, but I simply cannot make heads or tails of this proposal.

My general sense of this area is that the main problem is the dual meaning of T.Type. T.Type wants to simultaneously be the type of the type instance and the supertype of all subtype type instances. But this breaks down with protocols, because protocol existentials don't conform to themselves. So we end up with `T.Protocol`, which gets confusingly renamed when it crosses generic boundaries.

I think the answer here is to split these two roles:

1. `Metatype<T>` is the type of the type instance. `T.self` is of type `Metatype<T>`. (Yes, we can call it `T.metatype` if we want.) Subtype-supertype relationships don't translate directly to metaclasses; `Metatype<Subclass>` is not a subtype of `Metatype<Superclass>`.

2. `T.Subtype` (or `T.SubtypeMetatype`? `T.Conforming`? this needs bikeshedding) is the supertype of all metatypes for `T` and its subtypes. `T.Subtype` is sort of like a protocol, in that there are no concrete instances of it, so it makes no sense to instantiate it. For classes, it only includes required (i.e. inherited) initializers.

Happily, I believe—though I may be wrong—that we can mostly resyntax to fix this immediate problem. Adding new capabilities, like extending the metatypes of specific types and adding universal members, can wait (or mostly wait) for another day.

(But in general, I would like to see those added directly on `Metatype`, and I would like extending `Metatype<T>` with instance members to be equivalent to extending `T` with static/class members. I'd also like to conform metatypes to protocols, to somehow define `Metatype` in the standard library as a relatively ordinary Swift type, and to have a pony.)

   * Is the problem being addressed significant enough to warrant a change to Swift?

Yes.

   * Does this proposal fit well with the feel and direction of Swift?

I have no idea, because I can't understand the proposal.

   * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Most metatype (well, metaclass) systems I've worked with have been in more dynamic, runtime-oriented languages like Objective-C and Ruby.

   * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I've been following the threads since the beginning. (And I still don't understand the proposal.) I haven't been able to articulate my objections; honestly, I still can't, but I've run out of time to wait and see if I can figure things out.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Adrian Zubarev) #7

Hello Brent, thank you for your feedback on the review process of our proposal.

I think this proposal is a huge mess. I don’t understand why the split between Type and Metatype exists. I think Mirror seems half-baked; it ought to be omitted entirely until we can actually design a reflection system.
The reason why we took Mirror here, is because there can be metatypes that pretend to reflect T where the actual metatype could reflect U with relationship like U : T:

class Superclass {}
class Subclass : Superclass {}

let hidden: Any = Subclass()
let dynamicMetatype = hidden.dynamicType // Any.Type
dynamicMetatype as? Any.Type //=> NOT nil
dynamicMetatype as? Superclass.Type //=> NOT nil
dynamicMetatype as? Subclass.Type //=> NOT nil
That is the reason why a standalone non-generic type was needed to solve the problem with the ‘current’ Swift.

And I can’t even tell if these are actual problems. It’s possible that the design is just fine, but the proposal explains it poorly. At minimum, the proposal should be rewritten and the type names reconsidered. I’m not a person who gets confused by metatypes, but I simply cannot make heads or tails of this proposal.

My general sense of this area is that the main problem is the dual meaning of T.Type. T.Type wants to simultaneously be the type of the type instance and the supertype of all subtype type instances. But this breaks down with protocols, because protocol existentials don’t conform to themselves. So we end up with T.Protocol, which gets confusingly renamed when it crosses generic boundaries.

I think the answer here is to split these two roles:

Metatype<T> is the type of the type instance. T.self is of type Metatype<T>. (Yes, we can call it T.metatype if we want.)
If we don’t go into the direction of Type<T> there is no need to rename the current T.self magic to T.metatype, that was only considered for the Type<T> model. .self will be removed one day anyways (hopefully).

Subtype-supertype relationships don’t translate directly to metaclasses; Metatype<Subclass> is not a subtype of Metatype<Superclass>.
Why is that so, see the example above?!

T.Subtype (or T.SubtypeMetatype? T.Conforming? this needs bikeshedding) is the supertype of all metatypes for T and its subtypes. T.Subtype is sort of like a protocol, in that there are no concrete instances of it, so it makes no sense to instantiate it. For classes, it only includes required (i.e. inherited) initializers.
Happily, I believe—though I may be wrong—that we can mostly resyntax to fix this immediate problem. Adding new capabilities, like extending the metatypes of specific types and adding universal members, can wait (or mostly wait) for another day.

(But in general, I would like to see those added directly on Metatype, and I would like extending Metatype<T> with instance members to be equivalent to extending T with static/class members. I’d also like to conform metatypes to protocols, to somehow define Metatype in the standard library as a relatively ordinary Swift type, and to have a pony.)
This is an interesting suggestion you mentioned there. But I think that would imply that every member you’d add on the generic Metatype<T> would be automatically not available on any Swift type:

// Bikeshedding example:

buildin Metatype<T> : Hashable {
    var hashValue: Int { .. }
}

struct New {
    // NOT available anymore - even if it's needed for a different purpose
    static hashValue: Int { .. }
}
The issue can be solve if metatypes gain a bottleneck access to the type T, like Type<T>.metatype for example.

// Bikeshedding example:

buildin Metatype<T> : Hashable {
    var hashValue: Int { .. }
    var somethingToAccessT: T_XYZ { .. }
}

struct New {
    static hashValue: Int { .. } // available again
}
If we now compare this to our Type<T> model, we realize that the huge downside of Type<T> is that we cannot cast it around like we’d do with metatypes.

I’d appreciate the renaming of T.Type to Metatype<T>, but I believe this can’t be done without solving the issue with .Protocol first. Feel free to correct me, if I’m wrong here. :slight_smile:

In SE–0101 rationale Chris said, that the core team considered to move size to types but dropped the idea because it would require T.self.

If the core team and the community strongly feels it would be better to introduce a new scoped buildin type (not necessarily named buildin), which would be only visible in stdlib, we might revision our proposal and shrink it down to the minimum breaking changes for Swift 3. Of course such a new scoped type can be introduces post Swift 3 to gain extensibility.

Steps I have in my mind are:

Rename T.Type to Metatype<T> today and resolve the issue with .Protocol somehow (I’m not a compiler expert).
I’d rename type(of:) from SE–0096 to metatype(of:) (or better dynamicMetatype<T>(of instance: T) -> Metatype<T>; not sure why ‘dynamic’ was dropped)
Drop the idea with Mirror, see below.
Come back post Swift 3 and talk about a new buildin extensible scoped type for metatypes with implicit inheritance ability like U : T, which merges the static and dynamic parts of Mirror and Type<T>.
// Future bikeshedding:

buildin Metatype<T> : Hashable, CustomStringConvertible, CustomDebugStringConvertible {

    /// Creates an instance that reflects `T`.
    /// Example: `let type = T.self`
    public init()
     
    public static var somethingToAccessT: T_XYZ { get }
    public var somethingToAccessT: T_XYZ { get }

    public static var size: Int { get }
    public static var stride: Int { get }
    public static var alignment: Int { get }

    public var size: Int { get }
    public var stride: Int { get }
    public var alignment: Int { get }
     
    public var hashValue: Int { get }
    public var description: String { get }
    public var debugDescription: String { get }
}

func ==<T>(lhs: Metatype<T>, rhs: Metatype<T>) -> Bool {
    return lhs.hashValue == rhs.hashValue
}
If we can introduce this later, we might be able to drop the closed MemoryLayout enum then.

let metatype: Metatype<SomeType> = SomeType.self // or SomeType when `.self` is dropped
metatype.size // returns the size of `SomeType`
metatype.somethingToAccessT.staticMemember // from SomeType
metatype.somethingToAccessT.init // from SomeType

let hiddenMetatype: Metatype<Any> = metatype

(hiddenMetatype as? SomeType)?.somethingToAccessT

[Metatype<Any>: String] = [Int.self: "hello", Any.self: "swift"]
The last ideas are my personal ideas which I do believe reflects some of your suggestions.

Anton might have a different point of view here.

···

--
Adrian Zubarev
Sent with Airmail


(L Mihalkovic) #8

Regards
LM
(From mobile)

Hello Brent, thank you for your feedback on the review process of our proposal.

I think this proposal is a huge mess. I don’t understand why the split between Type and Metatype exists. I think Mirror seems half-baked; it ought to be omitted entirely until we can actually design a reflection system.
The reason why we took Mirror here, is because there can be metatypes that pretend to reflect T where the actual metatype could reflect U with relationship like U : T:

class Superclass {}
class Subclass : Superclass {}

let hidden: Any = Subclass()
let dynamicMetatype = hidden.dynamicType // Any.Type
dynamicMetatype as? Any.Type //=> NOT nil
dynamicMetatype as? Superclass.Type //=> NOT nil
dynamicMetatype as? Subclass.Type //=> NOT nil
That is the reason why a standalone non-generic type was needed to solve the problem with the ‘current’ Swift.

And I can’t even tell if these are actual problems. It’s possible that the design is just fine, but the proposal explains it poorly. At minimum, the proposal should be rewritten and the type names reconsidered. I’m not a person who gets confused by metatypes, but I simply cannot make heads or tails of this proposal.

The most immediate issue is that this is a set of possible tactical moves without a strategy to justify why they are the right ones. There is no doubt that some are good, but without a clear plan of what reflection is intended to provide in swift, then it looks like a random exercise.

Joe's idea of slicing them apart is interesting and likely what will happen if he says so, but in my mind it will push further away the fundamental question of giving a scope to reflection in swift. As i said privately, there are a lot of good papers out there exploring the different facets. The answer belongs to the core team: if swift is mostly for all 7-to-77 with an ipad, then what's in swift today is already too much, if on the other hand the goal is to help with writing efficient dynamic language runtimes in swift, then this proposal will need lots of TLC.

···

On Jul 21, 2016, at 4:59 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

My general sense of this area is that the main problem is the dual meaning of T.Type. T.Type wants to simultaneously be the type of the type instance and the supertype of all subtype type instances. But this breaks down with protocols, because protocol existentials don’t conform to themselves. So we end up with T.Protocol, which gets confusingly renamed when it crosses generic boundaries.

I think the answer here is to split these two roles:

Metatype<T> is the type of the type instance. T.self is of type Metatype<T>. (Yes, we can call it T.metatype if we want.)
If we don’t go into the direction of Type<T> there is no need to rename the current T.self magic to T.metatype, that was only considered for the Type<T> model. .self will be removed one day anyways (hopefully).

Subtype-supertype relationships don’t translate directly to metaclasses; Metatype<Subclass> is not a subtype of Metatype<Superclass>.
Why is that so, see the example above?!

T.Subtype (or T.SubtypeMetatype? T.Conforming? this needs bikeshedding) is the supertype of all metatypes for T and its subtypes. T.Subtype is sort of like a protocol, in that there are no concrete instances of it, so it makes no sense to instantiate it. For classes, it only includes required (i.e. inherited) initializers.
Happily, I believe—though I may be wrong—that we can mostly resyntax to fix this immediate problem. Adding new capabilities, like extending the metatypes of specific types and adding universal members, can wait (or mostly wait) for another day.

(But in general, I would like to see those added directly on Metatype, and I would like extending Metatype<T> with instance members to be equivalent to extending T with static/class members. I’d also like to conform metatypes to protocols, to somehow define Metatype in the standard library as a relatively ordinary Swift type, and to have a pony.)
This is an interesting suggestion you mentioned there. But I think that would imply that every member you’d add on the generic Metatype<T> would be automatically not available on any Swift type:

// Bikeshedding example:

buildin Metatype<T> : Hashable {
    var hashValue: Int { .. }
}

struct New {
    // NOT available anymore - even if it's needed for a different purpose
    static hashValue: Int { .. }
}
The issue can be solve if metatypes gain a bottleneck access to the type T, like Type<T>.metatype for example.

// Bikeshedding example:

buildin Metatype<T> : Hashable {
    var hashValue: Int { .. }
    var somethingToAccessT: T_XYZ { .. }
}

struct New {
    static hashValue: Int { .. } // available again
}
If we now compare this to our Type<T> model, we realize that the huge downside of Type<T> is that we cannot cast it around like we’d do with metatypes.

I’d appreciate the renaming of T.Type to Metatype<T>, but I believe this can’t be done without solving the issue with .Protocol first. Feel free to correct me, if I’m wrong here. :slight_smile:

In SE–0101 rationale Chris said, that the core team considered to move size to types but dropped the idea because it would require T.self.

If the core team and the community strongly feels it would be better to introduce a new scoped buildin type (not necessarily named buildin), which would be only visible in stdlib, we might revision our proposal and shrink it down to the minimum breaking changes for Swift 3. Of course such a new scoped type can be introduces post Swift 3 to gain extensibility.

Steps I have in my mind are:

Rename T.Type to Metatype<T> today and resolve the issue with .Protocol somehow (I’m not a compiler expert).
I’d rename type(of:) from SE–0096 to metatype(of:) (or better dynamicMetatype<T>(of instance: T) -> Metatype<T>; not sure why ‘dynamic’ was dropped)
Drop the idea with Mirror, see below.
Come back post Swift 3 and talk about a new buildin extensible scoped type for metatypes with implicit inheritance ability like U : T, which merges the static and dynamic parts of Mirror and Type<T>.
// Future bikeshedding:

buildin Metatype<T> : Hashable, CustomStringConvertible, CustomDebugStringConvertible {

    /// Creates an instance that reflects `T`.
    /// Example: `let type = T.self`
    public init()
     
    public static var somethingToAccessT: T_XYZ { get }
    public var somethingToAccessT: T_XYZ { get }

    public static var size: Int { get }
    public static var stride: Int { get }
    public static var alignment: Int { get }

    public var size: Int { get }
    public var stride: Int { get }
    public var alignment: Int { get }
     
    public var hashValue: Int { get }
    public var description: String { get }
    public var debugDescription: String { get }
}

func ==<T>(lhs: Metatype<T>, rhs: Metatype<T>) -> Bool {
    return lhs.hashValue == rhs.hashValue
}
If we can introduce this later, we might be able to drop the closed MemoryLayout enum then.

let metatype: Metatype<SomeType> = SomeType.self // or SomeType when `.self` is dropped
metatype.size // returns the size of `SomeType`
metatype.somethingToAccessT.staticMemember // from SomeType
metatype.somethingToAccessT.init // from SomeType

let hiddenMetatype: Metatype<Any> = metatype

(hiddenMetatype as? SomeType)?.somethingToAccessT

[Metatype<Any>: String] = [Int.self: "hello", Any.self: "swift"]
The last ideas are my personal ideas which I do believe reflects some of your suggestions.

Anton might have a different point of view here.

--
Adrian Zubarev
Sent with Airmail
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Adrian Zubarev) #9

Sliced revision is almost done. We would like to focus on two things: `Metatype<T>` and `metype(of:)`. I’ll post it here soon before submitting a PR.

···

--
Adrian Zubarev
Sent with Airmail


(Adrian Zubarev) #10

Here is the new revised draft: https://gist.github.com/DevAndArtist/f7da7d7338eedb40adb9c5631a34aee1

We’d like to hear your feedback before we submit this revision. It’s unusual for such a quick revision, but it’s clearly was asked by Joe Groff and the feedback from the community.

Introduction

This proposal renames the current metatype T.Type notation and the global function from SE–0096 to match the changes.

Swift-evolution threads:

[Review] SE–0126: Refactor Metatypes, repurpose T[dot]self and Mirror
[Proposal] Refactor Metatypes, repurpose T[dot]self and Mirror
[Discussion] Seal T.Type into Type<T>
Motivation

In Swift metatypes have the following notation: T.Type

As already showed in SE–0096 and SE–0090 the Swift community strongly is in favor of (re)moving magical intstance or type properties.

SE–0096 moves instanceOfT.dynamicType to type<T>(of: T) -> T.Type.

SE–0090 aims to remove .self completely.

We propose to rename T.Type to a generic-like notation Metatype<T>. To be able to achieve this notation we have to resolve a few issues first.

Known issues of metatypes:

Assume this function that checks if an Int type conforms to a specific protocol. This check uses current model of metatypes combined in a generic context:

func intConforms<T>(to _: T.Type) -> Bool {
   return Int.self is T.Type
}

intConforms(to: CustomStringConvertible.self) //=> false

Int.self is CustomStringConvertible.Type //=> true
[1] When T is a protocol P, T.Type is the metatype of the protocol type itself, P.Protocol. Int.self is not P.self.

[2] There isn’t a way to generically expression P.Type yet.

[3] The syntax would have to be changed in the compiler to get something that behaves like .Type today.

Written by Joe Groff: [1] [2] [3]
A possible workaround might look like the example below, but does not allow to decompose P.Type:

func intConforms<T>(to _: T.Type) -> Bool {
  return Int.self is T
}

intConforms(to: CustomStringConvertible.Type.self) //=> true
We can extend this issue and find the second problem by checking against the metatype of Any:

func intConforms<T>(to _: T.Type) -> Bool {
    return Int.self is T
}

intConforms(to: Any.Type.self) //=> true

intConforms(to: Any.self) //=> true

Int.self is Any.Type //=> Always true
When using Any the compiler does not require .Type at all and returns true for both variations.

The third issue will show itself whenever we would try to check protocol relationship with another protocol. Currently there is no way (that we know of) to solve this problem:

protocol P {}
protocol R : P {}

func rIsSubtype<T>(of _: T.Type) -> Bool {
    return R.self is T
}

rIsSubtype(of: P.Type.self) //=> false

R.self is Any.Type //=> Always true
R.self is P.Type //=> true
R.self is R.Type //=> true
We also believe that this issue is the reason why the current global functions sizeof, strideof and alignof make use of generic <T>(_: T.Type) declaration notation instead of (_: Any.Type).

Proposed solution

Rename any occurrence of T.Type and T.Protocol to Metatype<T>.

Revise metatypes internally.

When T is a protocol, T.self should always return an instance of Metatype<T> (old T.Type) and never a T.Protocol. Furthermore, metatypes should reflect the same type relationship behavior like the actual types themselves.

To match the correct meaning and usage of the noun ‘Metatype’ from this proposal, we also propose to rename the global function from SE–0096:

before: public func type<T>(of instance: T) -> T.Type
after: public func metatype<T>(of instance: T) -> Metatype<T>
Examples:

protocol P {}
protocol R : P {}
class A : P {}
class B : A, R {}

func `is`<T>(metatype: Metatype<Any>, also _: Metatype<T> ) -> Bool {
    return metatype is Metatype<T>
}

`is`(metatype: R.self, also: Any.self) //=> true | Currently: false
`is`(metatype: R.self, also: P.self) //=> true | Currently: false
`is`(metatype: R.self, also: R.self) //=> true

`is`(metatype: B.self, also: Any.self) //=> true | Currently: false
`is`(metatype: B.self, also: P.self) //=> true | Currently: false
`is`(metatype: B.self, also: R.self) //=> true | Currently: false
`is`(metatype: B.self, also: A.self) //=> true
`is`(metatype: B.self, also: B.self) //=> true

func cast<T>(metatype: Metatype<Any>, to _: Metatype<T>) -> Metatype<T>? {
    return metatype as? Metatype<T>
}

cast(metatype: R.self, to: Any.self) //=> an Optional<Metatype<Any>> | Currently: nil
cast(metatype: R.self, to: P.self) //=> an Optional<Metatype<P>> | Currently: nil
cast(metatype: R.self, to: R.self) //=> an Optional<Metatype<R>> | Currently: an Optional<R.Protocol>

let anyR: Any.Type = R.self
let r = cast(metatype: anyR, to: R.self) //=> an Optional<Metatype<R>> | Currently: an Optional<R.Protocol>

cast(metatype: B.self, to: Any.self) //=> an Optional<Metatype<Any>> | Currently: nil
cast(metatype: B.self, to: P.self) //=> an Optional<Metatype<P>> | Currently: nil
cast(metatype: B.self, to: R.self) //=> an Optional<Metatype<R>> | Currently: nil
cast(metatype: B.self, to: A.self) //=> an Optional<Metatype<A>>
cast(metatype: B.self, to: B.self) //=> an Optional<Metatype<B>>

let pB: P.Type = B.self
let b = cast(metatype: pB, to: B.self) //=> an Optional<Metatype<B>>
Impact on existing code

This is a source-breaking change that can be automated by a migrator. Any occurrence of T.Type or T.Protocol will be simply renamed to Metatype<T>.

Alternatives considered

Alternatively it’s reasonable to consider to rename T.self to T.metatype.
It was considered to reserve Type<T> for different usage in the future.

···

--
Adrian Zubarev
Sent with Airmail

Am 21. Juli 2016 um 22:22:38, Adrian Zubarev (adrian.zubarev@devandartist.com) schrieb:

Sliced revision is almost done. We would like to focus on two things: `Metatype<T>` and `metype(of:)`. I’ll post it here soon before submitting a PR.

--
Adrian Zubarev
Sent with Airmail