[Revision] [Pitch] Rename `T.Type`


(Adrian Zubarev) #1

https://github.com/DevAndArtist/swift-evolution/blob/rename_t_dot_type/proposals/0126-rename-t-dot-type.md

Rename T.Type

Proposal: SE–0126
Authors: Adrian Zubarev, Anton Zhilin
Status: Revision
Review manager: Chris Lattner
Revision: 2
Previous Revisions: 1
Introduction

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

Swift-evolution threads:

[Pitch] Rename T.Type
[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


(Xiaodi Wu) #2

https://github.com/DevAndArtist/swift-evolution/blob/rename_t_dot_type/proposals/0126-rename-t-dot-type.md
------------------------------
Rename T.Type

   - Proposal: SE–0126
   <http://0126-refactor-metatypes-repurpose-t-dot-self-and-mirror.md>
   - Authors: Adrian Zubarev <https://github.com/DevAndArtist>, Anton
   Zhilin <https://github.com/Anton3>
   - Status: *Revision*
   - Review manager: Chris Lattner <http://github.com/lattner>
   - Revision: 2
   - Previous Revisions: 1
   <https://github.com/apple/swift-evolution/blob/83707b0879c83dcde778f8163f5768212736fdc2/proposals/0126-refactor-metatypes-repurpose-t-dot-self-and-mirror.md>

Introduction

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

Swift-evolution threads:

   - [Pitch] Rename T.Type
   - [Review] SE–0126: Refactor Metatypes, repurpose T[dot]self and Mirror
   - [Proposal] Refactor Metatypes, repurpose T[dot]self and Mirror
   <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160718/024772.html>
   - [Discussion] Seal T.Type into Type<T>
   <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160704/023818.html>

Motivation

For improved reader comprehension, this section could use some more
information and reorganization. Specifically, the structure should (IMO) be
refactored to have:

1. A consolidated section--which can be on the brief side--on the current
art (i.e., how do things currently work?). Some information is already
present, but the prose is not possible to follow unless one is already an
expert in the area. Please start each paragraph with a topic sentence
leading into an explanation in English, not just code, of the current
behavior. Perhaps you could used (attributed) quotations from existing
Swift documentation if necessary.

2. Subsequent to (1), a concise explanation in English (in addition to
Swift code, if desired, but the key is to have it also in English)
outlining the defects present in the current art. I know, for instance,
that type(of:) as approved can't quite be expressed in Swift code due to
issues related to existential metatypes. Could you elaborate on these
issues in a way that would set up your proposed solution?

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]
<https://twitter.com/jckarter/status/754420461404958721> [2]
<https://twitter.com/jckarter/status/754420624261472256> [3]
<https://twitter.com/jckarter/status/754425573762478080>

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>.

Why is this necessary? It is not clear from what you wrote in the
Motivation section. Naively, it would seem like the most straightforward
ways to remove the "magic" properties would be to repaint them `Type<T>`
and `Protocol<T>`. If you considered that most obvious choice and discarded
it (as I'm sure you have), what is the reasoning for suggesting
`Metatype<T>` instead?

   -

   Revise metatypes internally.

In what way? How would you want an implementer to tackle this bullet point?
What are the user-observable changes that will result, if any? If there
will be none, why is it part of the proposed solution?

   -

   -

   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.

If this is implemented, how will I then access the value currently returned
by `T.self`? Are you asserting that an instance of `T.Protocol` is never
useful, or are you providing an alternative way to get the same instance?

···

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

   -

   -

   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

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


(L Mihalkovic) #3

As unfocussed as original
Regards
(From mobile)

···

On Jul 22, 2016, at 12:40 AM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

https://github.com/DevAndArtist/swift-evolution/blob/rename_t_dot_type/proposals/0126-rename-t-dot-type.md

Rename T.Type

Proposal: SE–0126
Authors: Adrian Zubarev, Anton Zhilin
Status: Revision
Review manager: Chris Lattner
Revision: 2
Previous Revisions: 1
Introduction

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

Swift-evolution threads:

[Pitch] Rename T.Type
[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
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(David Hart) #4

I specifically agree with this point. I regard myself as a knowledgable Swift developer, but metatypes have always been a bit fuzzy for me, which refrained me from commenting on the proposal. If instead, the proposal tried to explain as succinctly as possible the current situation and its defects, I’m sure I’d have a higher chance of understand the problem at hand and commenting on it.

···

On 22 Jul 2016, at 01:41, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

1. A consolidated section--which can be on the brief side--on the current art (i.e., how do things currently work?). Some information is already present, but the prose is not possible to follow unless one is already an expert in the area. Please start each paragraph with a topic sentence leading into an explanation in English, not just code, of the current behavior. Perhaps you could used (attributed) quotations from existing Swift documentation if necessary.


(Taras Zakharko) #5

To be honest, I have difficulty with the terminology here. Why use the term ‚metatype‘ in the first place? Why not just ‚Type'? Or ‚TypeDescriptor‘ (in analogy to ObjectIdentifier)? What do we actually gain by the technical distinction between a type and a type of a type? I would understand it if we had the ability to construct higher-order types, such as custom metatypes or even metatype types in Swift.

But in general, I am sympathetic with the proposal.Swift type/metatype facilities are very confusing (I still don’t get how the .Type, .Self, .self etc. stuff works) and bringing some clarity will be most welcome.

— T.

···

On 22 Jul 2016, at 00:40, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

https://github.com/DevAndArtist/swift-evolution/blob/rename_t_dot_type/proposals/0126-rename-t-dot-type.md
Rename T.Type

Proposal: SE–0126 <x-msg://35/0126-refactor-metatypes-repurpose-t-dot-self-and-mirror.md>
Authors: Adrian Zubarev <https://github.com/DevAndArtist>, Anton Zhilin <https://github.com/Anton3>
Status: Revision
Review manager: Chris Lattner <http://github.com/lattner>
Revision: 2
Previous Revisions: 1 <https://github.com/apple/swift-evolution/blob/83707b0879c83dcde778f8163f5768212736fdc2/proposals/0126-refactor-metatypes-repurpose-t-dot-self-and-mirror.md>
Introduction

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

Swift-evolution threads:

[Pitch] Rename T.Type <applewebdata://86264528-D120-4E32-9AC9-034995F494C9>
[Review] SE–0126: Refactor Metatypes, repurpose T[dot]self and Mirror <applewebdata://86264528-D120-4E32-9AC9-034995F494C9>
[Proposal] Refactor Metatypes, repurpose T[dot]self and Mirror <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160718/024772.html>
[Discussion] Seal T.Type into Type<T> <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160704/023818.html>
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] <https://twitter.com/jckarter/status/754420461404958721> [2] <https://twitter.com/jckarter/status/754420624261472256> [3] <https://twitter.com/jckarter/status/754425573762478080>
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

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


(Chris Lattner) #6

As unfocussed as original

Please keep comments *constructive* on this list.

-Chris

···

On Jul 21, 2016, at 4:07 PM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

Regards
(From mobile)

On Jul 22, 2016, at 12:40 AM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

https://github.com/DevAndArtist/swift-evolution/blob/rename_t_dot_type/proposals/0126-rename-t-dot-type.md
Rename T.Type

Proposal: SE–0126 <x-msg://594/0126-refactor-metatypes-repurpose-t-dot-self-and-mirror.md>
Authors: Adrian Zubarev <https://github.com/DevAndArtist>, Anton Zhilin <https://github.com/Anton3>
Status: Revision
Review manager: Chris Lattner <http://github.com/lattner>
Revision: 2
Previous Revisions: 1 <https://github.com/apple/swift-evolution/blob/83707b0879c83dcde778f8163f5768212736fdc2/proposals/0126-refactor-metatypes-repurpose-t-dot-self-and-mirror.md>
Introduction

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

Swift-evolution threads:

[Pitch] Rename T.Type <applewebdata://1A857E6E-5ECA-433A-9669-6DB2B5E23BD0>
[Review] SE–0126: Refactor Metatypes, repurpose T[dot]self and Mirror <applewebdata://1A857E6E-5ECA-433A-9669-6DB2B5E23BD0>
[Proposal] Refactor Metatypes, repurpose T[dot]self and Mirror <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160718/024772.html>
[Discussion] Seal T.Type into Type<T> <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160704/023818.html>
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] <https://twitter.com/jckarter/status/754420461404958721> [2] <https://twitter.com/jckarter/status/754420624261472256> [3] <https://twitter.com/jckarter/status/754425573762478080>
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

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

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


(L Mihalkovic) #7

Regards
(From mobile)

To be honest, I have difficulty with the terminology here. Why use the term ‚metatype‘

It is the literature's terminology (types about types) and also the compiler's own naming.

···

On Jul 22, 2016, at 9:22 AM, Taras Zakharko via swift-evolution <swift-evolution@swift.org> wrote:

in the first place? Why not just ‚Type'? Or ‚TypeDescriptor‘ (in analogy to ObjectIdentifier)? What do we actually gain by the technical distinction between a type and a type of a type? I would understand it if we had the ability to construct higher-order types, such as custom metatypes or even metatype types in Swift.

But in general, I am sympathetic with the proposal.Swift type/metatype facilities are very confusing (I still don’t get how the .Type, .Self, .self etc. stuff works) and bringing some clarity will be most welcome.

— T.

On 22 Jul 2016, at 00:40, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

https://github.com/DevAndArtist/swift-evolution/blob/rename_t_dot_type/proposals/0126-rename-t-dot-type.md

Rename T.Type

Proposal: SE–0126
Authors: Adrian Zubarev, Anton Zhilin
Status: Revision
Review manager: Chris Lattner
Revision: 2
Previous Revisions: 1
Introduction

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

Swift-evolution threads:

[Pitch] Rename T.Type
[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

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

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


(Anton Zhilin) #8

For everyone who doesn't understand metatypes and our problem, please see:

https://gist.github.com/Anton3/25a66751812f14f76cacc5e382339522

Read it from beginning to ending and ask if you don't understand something!


(Taras Zakharko) #9

Regards
(From mobile)

To be honest, I have difficulty with the terminology here. Why use the term ‚metatype‘

It is the literature's terminology (types about types) and also the compiler's own naming.

I am certainly not contesting these facts. However, I am not sure how helpful this particular terminology is in the relevant context. After all, we are talking here about operations on types themselves, not types of a type. While it is true that any type variable/parameter itself is of a metatype type, I don’t see any utility gained by making this fact explicit. Something like Type or TypeInfo accomplishes the same and is probably easier to understand.

For instance, I have difficulty understanding why you suggest to rename type(of:) to metatype(of:). Unless I am completely confused, the return value is a type, isn’t it? its just that the type of the return value is a metatype.

This is a different thing in languages like Python, where metatypes have a clear practical purpose (it is possible to directly create and manipulate metatypes).

— T.

P.S. I hope my naive questions are not too inappropriate. I am honestly trying to understand the topic. While I do have some background in higher-order logic and type theory, and I have done a fair share of programming with types and types of types, the way Swift works in this regard eludes me.

···

On 22 Jul 2016, at 12:11, L. Mihalkovic <laurent.mihalkovic@gmail.com> wrote:
On Jul 22, 2016, at 9:22 AM, Taras Zakharko via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

in the first place? Why not just ‚Type'? Or ‚TypeDescriptor‘ (in analogy to ObjectIdentifier)? What do we actually gain by the technical distinction between a type and a type of a type? I would understand it if we had the ability to construct higher-order types, such as custom metatypes or even metatype types in Swift.

But in general, I am sympathetic with the proposal.Swift type/metatype facilities are very confusing (I still don’t get how the .Type, .Self, .self etc. stuff works) and bringing some clarity will be most welcome.

— T.

On 22 Jul 2016, at 00:40, Adrian Zubarev via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

https://github.com/DevAndArtist/swift-evolution/blob/rename_t_dot_type/proposals/0126-rename-t-dot-type.md
Rename T.Type

Proposal: SE–0126 <x-msg://35/0126-refactor-metatypes-repurpose-t-dot-self-and-mirror.md>
Authors: Adrian Zubarev <https://github.com/DevAndArtist>, Anton Zhilin <https://github.com/Anton3>
Status: Revision
Review manager: Chris Lattner <http://github.com/lattner>
Revision: 2
Previous Revisions: 1 <https://github.com/apple/swift-evolution/blob/83707b0879c83dcde778f8163f5768212736fdc2/proposals/0126-refactor-metatypes-repurpose-t-dot-self-and-mirror.md>
Introduction

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

Swift-evolution threads:

[Pitch] Rename T.Type <applewebdata://5920FB3D-680D-42A4-A834-AF48FAFD667D>
[Review] SE–0126: Refactor Metatypes, repurpose T[dot]self and Mirror <applewebdata://5920FB3D-680D-42A4-A834-AF48FAFD667D>
[Proposal] Refactor Metatypes, repurpose T[dot]self and Mirror <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160718/024772.html>
[Discussion] Seal T.Type into Type<T> <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160704/023818.html>
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] <https://twitter.com/jckarter/status/754420461404958721> [2] <https://twitter.com/jckarter/status/754420624261472256> [3] <https://twitter.com/jckarter/status/754425573762478080>
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

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

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


(Vladimir) #10

Thank you for the article. Very informative.

So, I believe core team can answer the question : "..why P.Protocol is needed" and if we can remove it without problems.

Small fix - A&B should have ': HasStatic' and closing bracket here:

protocol HasStatic { static func staticMethod() }
struct A { static func staticMethod() -> String { return "A" }
struct B { static func staticMethod() -> String { return "B" }

···

On 22.07.2016 14:40, Anton Zhilin via swift-evolution wrote:

For everyone who doesn't understand metatypes and our problem, please see:

https://gist.github.com/Anton3/25a66751812f14f76cacc5e382339522

Read it from beginning to ending and ask if you don't understand something!

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


(Adrian Zubarev) #11

Hello everyone,

recently I was pinged on twitter to a conversation between Jacob Bandes-Storch, Joe Groff and Slava Pestov.

Here is the conversation covering a few more facts about the mysterious .Protocol:

[Jacob Bandes-Storch] Was hoping to just define type<T>(of x: T) -> T.Type and move impl of emitMetatypeOfValue() there.

[Joe Groff] Yeah, that won’t do the right thing for existentials compared to x.dynamicType.

[Jacob Bandes-Storch] When you say “do the right thing” you mean the return type? Shouldn’t type(of x: Proto) -> Proto.Type?

[Slava Pestov] Right, but if T := P, then T.Type is P.Protocol, not P.Type

[Jacob Bandes-Storch] Mind bending… Suppose T : P, x : P = T(), then type(of: x) returns T, and T: P.Type. What am I missing?

[Joe Groff] P.Type is really Any<P.Type>, and P.Protocol is really (Any<P>).Type. If T == Any<P>, T.Type == latter

[Joe Groff] dynamicType is different for existentials: open existential, take opened metatype, erase to e.metatype

[Jacob Bandes-Storch] Now I’m confused by current behavior: GIST … isn’t dynamicType’s job to return T.self?

[Joe Groff] invokes `foo() on the opened type, then re-closes an existential around the result if Self is involved

[Jacob Bandes-Storch] But this does what I’d expect: GIST

[Joe Groff] Right, member lookup also implicitly opens an existential.

[Jacob Bandes-Storch] Point being that there’s no way to do this for generic params?

[Joe Groff] Not in argument position. Only ‘self’ gets this magic behavior.

[Jacob Bandes-Storch] Is that a bug or feature? Seems to me dynamicType should always be able to get the actual runtime type.

[Joe Groff] Consider this situation:

func foo<T>(x:T) -> (T.Type, T.Type) {
   return (T.self, x.dynamicType)
}
[Jacob Bandes-Storch] Still struggling to see what’s wrong with returning “real” type. What can be subst. for `T that breaks it?

[Joe Groff] Consider T == P with x.dynamicType trying to produce the existential dynamic type.

[Jacob Bandes-Storch] I think I’m mostly confused because P.Type vs. P.Protocol is really non-obvious. Has renaming been discussed?

[Joe Groff] The gotcha mainly comes up if you try to replicate the builtin behavior. Most people don’t try to do that.

[Jacob Bandes-Storch] Would it make sense to disallow x.dynamicType in such cases? Gotcha would be less confusing if forced to say `T.self.

···

--
Adrian Zubarev
Sent with Airmail

Am 22. Juli 2016 um 14:47:08, Vladimir.S via swift-evolution (swift-evolution@swift.org) schrieb:

Thank you for the article. Very informative.

So, I believe core team can answer the question : "..why P.Protocol is
needed" and if we can remove it without problems.

Small fix - A&B should have ': HasStatic' and closing bracket here:

protocol HasStatic { static func staticMethod() }
struct A { static func staticMethod() -> String { return "A" }
struct B { static func staticMethod() -> String { return "B" }

On 22.07.2016 14:40, Anton Zhilin via swift-evolution wrote:

For everyone who doesn't understand metatypes and our problem, please see:

https://gist.github.com/Anton3/25a66751812f14f76cacc5e382339522

Read it from beginning to ending and ask if you don't understand something!

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

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


(Anton Zhilin) #12

Interesting, it looks like only Joe Groff understands what .Protocol means
and considers it important. And a couple others, maybe.

Copying my metatypes explanation link:
For everyone who doesn't understand metatypes and our problem, please see
https://gist.github.com/Anton3/25a66751812f14f76cacc5e382339522

···

2016-07-22 16:07 GMT+03:00 Adrian Zubarev via swift-evolution < swift-evolution@swift.org>:

Hello everyone,

recently I was pinged on twitter to a conversation between Jacob
Bandes-Storch, Joe Groff and Slava Pestov.

Here is the conversation covering a few more facts about the mysterious
.Protocol:

*[Jacob Bandes-Storch]* Was hoping to just define type<T>(of x: T) ->
T.Type and move impl of emitMetatypeOfValue() there.

*[Joe Groff]* Yeah, that won’t do the right thing for existentials
compared to x.dynamicType.

*[Jacob Bandes-Storch]* When you say “do the right thing” you mean the
return type? Shouldn’t type(of x: Proto) -> Proto.Type?

*[Slava Pestov]* Right, but if T := P, then T.Type is P.Protocol, not
P.Type

*[Jacob Bandes-Storch]* Mind bending… Suppose T : P, x : P = T(), then type(of:
x) returns T, and T: P.Type. What am I missing?

*[Joe Groff]* P.Type is really Any<P.Type>, and P.Protocol is really
(Any<P>).Type. If T == Any<P>, T.Type == latter

*[Joe Groff]* dynamicType is different for existentials: open
existential, take opened metatype, erase to e.metatype

*[Jacob Bandes-Storch]* Now I’m confused by current behavior: GIST
<https://gist.github.com/jtbandes/7624fef93eb23010c032b2d1fd3674be#file-dynamictype-swift-L12>
… isn’t dynamicType’s job to return T.self?

*[Joe Groff]* invokes `foo() on the opened type, then re-closes an
existential around the result if Self is involved

*[Jacob Bandes-Storch]* But this does what I’d expect: GIST
<https://gist.github.com/jtbandes/7624fef93eb23010c032b2d1fd3674be#file-dynamictype-swift-L23>

*[Joe Groff]* Right, member lookup also implicitly opens an existential.

*[Jacob Bandes-Storch]* Point being that there’s no way to do this for
generic params?

*[Joe Groff]* Not in argument position. Only ‘self’ gets this magic
behavior.

*[Jacob Bandes-Storch]* Is that a bug or feature? Seems to me dynamicType
should always be able to get the actual runtime type.

*[Joe Groff]* Consider this situation:

func foo<T>(x:T) -> (T.Type, T.Type) {
   return (T.self, x.dynamicType)
}

*[Jacob Bandes-Storch]* Still struggling to see what’s wrong with
returning “real” type. What can be subst. for `T that breaks it?

*[Joe Groff]* Consider T == P with x.dynamicType trying to produce the
existential dynamic type.

*[Jacob Bandes-Storch]* I think I’m mostly confused because P.Type vs.
P.Protocol is really non-obvious. Has renaming been discussed?

*[Joe Groff]* The gotcha mainly comes up if you try to replicate the
builtin behavior. Most people don’t try to do that.

*[Jacob Bandes-Storch]* Would it make sense to disallow x.dynamicType in
such cases? Gotcha would be less confusing if forced to say `T.self.

--
Adrian Zubarev
Sent with Airmail

Am 22. Juli 2016 um 14:47:08, Vladimir.S via swift-evolution (
swift-evolution@swift.org) schrieb:

Thank you for the article. Very informative.

So, I believe core team can answer the question : "..why P.Protocol is
needed" and if we can remove it without problems.

Small fix - A&B should have ': HasStatic' and closing bracket here:

protocol HasStatic { static func staticMethod() }
struct A { static func staticMethod() -> String { return "A" }
struct B { static func staticMethod() -> String { return "B" }

On 22.07.2016 14:40, Anton Zhilin via swift-evolution wrote:
> For everyone who doesn't understand metatypes and our problem, please
see:
>
> https://gist.github.com/Anton3/25a66751812f14f76cacc5e382339522
>
> Read it from beginning to ending and ask if you don't understand
something!
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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


(Karl) #13

I wouldn’t be surprised if there are less than a handful of people outside of the Swift team who understand what .Protocol means.

Most of us just want to create generic objects based on their conformance to an initialiser in a protocol:

protocol Constructable {
  init()
}

func construct<C:Constructable>() -> C {
  return C() // ERROR
}

Karl

···

On 22 Jul 2016, at 15:19, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:

Interesting, it looks like only Joe Groff understands what .Protocol means and considers it important. And a couple others, maybe.

Copying my metatypes explanation link:
For everyone who doesn't understand metatypes and our problem, please see
https://gist.github.com/Anton3/25a66751812f14f76cacc5e382339522

2016-07-22 16:07 GMT+03:00 Adrian Zubarev via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:
Hello everyone,

recently I was pinged on twitter to a conversation between Jacob Bandes-Storch, Joe Groff and Slava Pestov.

Here is the conversation covering a few more facts about the mysterious .Protocol:

[Jacob Bandes-Storch] Was hoping to just define type<T>(of x: T) -> T.Type and move impl of emitMetatypeOfValue() there.

[Joe Groff] Yeah, that won’t do the right thing for existentials compared to x.dynamicType.

[Jacob Bandes-Storch] When you say “do the right thing” you mean the return type? Shouldn’t type(of x: Proto) -> Proto.Type?

[Slava Pestov] Right, but if T := P, then T.Type is P.Protocol, not P.Type

[Jacob Bandes-Storch] Mind bending… Suppose T : P, x : P = T(), then type(of: x) returns T, and T: P.Type. What am I missing?

[Joe Groff] P.Type is really Any<P.Type>, and P.Protocol is really (Any<P>).Type. If T == Any<P>, T.Type == latter

[Joe Groff] dynamicType is different for existentials: open existential, take opened metatype, erase to e.metatype

[Jacob Bandes-Storch] Now I’m confused by current behavior: GIST <https://gist.github.com/jtbandes/7624fef93eb23010c032b2d1fd3674be#file-dynamictype-swift-L12> … isn’t dynamicType’s job to return T.self?

[Joe Groff] invokes `foo() on the opened type, then re-closes an existential around the result if Self is involved

[Jacob Bandes-Storch] But this does what I’d expect: GIST <https://gist.github.com/jtbandes/7624fef93eb23010c032b2d1fd3674be#file-dynamictype-swift-L23>
[Joe Groff] Right, member lookup also implicitly opens an existential.

[Jacob Bandes-Storch] Point being that there’s no way to do this for generic params?

[Joe Groff] Not in argument position. Only ‘self’ gets this magic behavior.

[Jacob Bandes-Storch] Is that a bug or feature? Seems to me dynamicType should always be able to get the actual runtime type.

[Joe Groff] Consider this situation:

func foo<T>(x:T) -> (T.Type, T.Type) {
   return (T.self, x.dynamicType)
}
[Jacob Bandes-Storch] Still struggling to see what’s wrong with returning “real” type. What can be subst. for `T that breaks it?

[Joe Groff] Consider T == P with x.dynamicType trying to produce the existential dynamic type.

[Jacob Bandes-Storch] I think I’m mostly confused because P.Type vs. P.Protocol is really non-obvious. Has renaming been discussed?

[Joe Groff] The gotcha mainly comes up if you try to replicate the builtin behavior. Most people don’t try to do that.

[Jacob Bandes-Storch] Would it make sense to disallow x.dynamicType in such cases? Gotcha would be less confusing if forced to say `T.self.

--
Adrian Zubarev
Sent with Airmail

Am 22. Juli 2016 um 14:47:08, Vladimir.S via swift-evolution (swift-evolution@swift.org <mailto:swift-evolution@swift.org>) schrieb:

Thank you for the article. Very informative.

So, I believe core team can answer the question : "..why P.Protocol is
needed" and if we can remove it without problems.

Small fix - A&B should have ': HasStatic' and closing bracket here:

protocol HasStatic { static func staticMethod() }
struct A { static func staticMethod() -> String { return "A" }
struct B { static func staticMethod() -> String { return "B" }

On 22.07.2016 14:40, Anton Zhilin via swift-evolution wrote:
> For everyone who doesn't understand metatypes and our problem, please see:
>
> https://gist.github.com/Anton3/25a66751812f14f76cacc5e382339522
>
> Read it from beginning to ending and ask if you don't understand something!
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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


(Anton Zhilin) #14

In your example, there is no problem, because we can disambiguate based on
return type:

let c = construct() as SomeConstrictible

Metatypes are only really needed, when target type would not appear in the
signature otherwise.
And I kind-of understand the decision of not adding explicit generic
function specialization, because otherwise there would be double
specialization in generic constructors, like this:

struct Example<T> {
    init<U>()
}
Example<Int><Double>

And that would look awful. If I'm not mistaken, such initializers exist in
the standard library.

···

2016-07-22 17:32 GMT+03:00 Karl <razielim@gmail.com>:

I wouldn’t be surprised if there are less than a handful of people outside
of the Swift team who understand what .Protocol means.

Most of us just want to create generic objects based on their conformance
to an initialiser in a protocol:

protocol Constructable {
init()
}

func construct<C:Constructable>() -> C {
return C() // ERROR
}


(David Hart) #15

Isn't the solution to a lot of these issues allowing explicit generalization instead of this meta type business?

···

On 22 Jul 2016, at 17:03, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:

2016-07-22 17:32 GMT+03:00 Karl <razielim@gmail.com>:

I wouldn’t be surprised if there are less than a handful of people outside of the Swift team who understand what .Protocol means.

Most of us just want to create generic objects based on their conformance to an initialiser in a protocol:

protocol Constructable {
  init()
}

func construct<C:Constructable>() -> C {
  return C() // ERROR
}

In your example, there is no problem, because we can disambiguate based on return type:

let c = construct() as SomeConstrictible

Metatypes are only really needed, when target type would not appear in the signature otherwise.
And I kind-of understand the decision of not adding explicit generic function specialization, because otherwise there would be double specialization in generic constructors, like this:

struct Example<T> {
    init<U>()
}
Example<Int><Double>

And that would look awful. If I'm not mistaken, such initializers exist in the standard library.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Anton Zhilin) #16

And what would you suggest for "double generics" in initializers?
ExampleType<Int><Double>() // not good

···

2016-07-22 18:51 GMT+03:00 David Hart <david@hartbit.com>:

Isn't the solution to a lot of these issues allowing explicit
generalization instead of this meta type business?


(David Hart) #17

Where do these double generics come from? Never saw them...

···

On 22 Jul 2016, at 17:54, Anton Zhilin <antonyzhilin@gmail.com> wrote:

2016-07-22 18:51 GMT+03:00 David Hart <david@hartbit.com>:

Isn't the solution to a lot of these issues allowing explicit generalization instead of this meta type business?

And what would you suggest for "double generics" in initializers?
ExampleType<Int><Double>() // not good


(Chéyo Jiménez) #18

I'm finding it really hard to see the advantage of this proposal with out reconciling the possibility of .self going away. I think this should be postponed after .self is reviewed in swift 4. Premature optimization imo.

···

On Jul 22, 2016, at 3:20 PM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

Where do these double generics come from? Never saw them...

On 22 Jul 2016, at 17:54, Anton Zhilin <antonyzhilin@gmail.com> wrote:

2016-07-22 18:51 GMT+03:00 David Hart <david@hartbit.com>:

Isn't the solution to a lot of these issues allowing explicit generalization instead of this meta type business?

And what would you suggest for "double generics" in initializers?
ExampleType<Int><Double>() // not good

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


(Adrian Zubarev) #19

Updated with changes written by Anton: https://github.com/DevAndArtist/swift-evolution/blob/rename_t_dot_type/proposals/0126-rename-t-dot-type.md

Introduction

This proposal renames T.Type to Metatype<T>, renames type(of:) to metatype(of:) and removes P.Protocol metatypes.

Swift-evolution threads:

[Revision] [Pitch] Rename T.Type
[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

Explanation of metatypes
Current behavior of .Protocol

For protocols P, besides normal P.Type, there is also a “restricting metatype” P.Protocol that is the same as P.Type, except that it can only reflect P itself and not any of its subtypes:

Int.self is CustomStringConvertible.Type //=> true
Int.self is CustomStringConvertible.Protocol //=> false
Even without P.Protocol, we can test for equality:

Int.self is CustomStringConvertible.Type //=> true
Int.self == CustomStringConvertible.self //=> false
For protocols P, P.self returns a P.Protocol, not P.Type:

let metatype = CustomStringConvertible.self
print(type(of: metatype)) //=> CustomStringConvertible.Protocol
In practise, the existence of P.Protocol creates problems. If T is a generic parameter, then T.Type turns into P.Protocol if a protocol P is passed:

func printMetatype<T>(_ meta: T.Type) {
    print(dynamicType(meta))
    let copy = T.self
    print(dynamicType(copy))
}

printMetatype(CustomStringConvertible.self) //=> CustomStringConvertible.Protocol x2
Lets review the following situation:

func isIntSubtype<T>(of: T.Type) -> Bool {
    return Int.self is T.Type
}

isIntSubtype(of: CustomStringConvertible.self) //=> false
Now we understand that because T is a protocol P, T.Type turns into a P.Protocol, and we get the confusing behaviour.

Summing up issues with P.Protocol, it does not bring any additional functionality (we can test .Types for is and for ==), but tends to appear unexpectedly and break subtyping with metatypes.

Even more issues with .Protocol

[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]
There is a workaround for isIntSubtype example above. If we pass a P.Type.Type, then it turns into P.Type.Protocol, but it is still represented with .Type in generic contexts. If we manage to drop outer .Type, then we get P.Type:

func isIntSubtype<T>(of _: T.Type) -> Bool {
  return Int.self is T // not T.Type here anymore
}

isIntSubtype(of: CustomStringConvertible.Type.self) //=> true
In this call, T = CustomStringConvertible.Type. We can extend this issue and find the second problem by checking against the metatype of Any:

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

isIntSubtype(of: Any.Type.self) //=> true

isIntSubtype(of: Any.self) //=> true
When using Any, the compiler does not require .Type and returns true for both variations.

The third issue shows itself when we try to check protocol relationship with another protocol. Currently, there is no way (that we know of) to solve this problem:

protocol Parent {}
protocol Child : Parent {}

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

isChildSubtype(of: Parent.Type.self) //=> false
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).

Magical members

There were the following “magical” members of all types/instances:

.dynamicType, which was replaced with type(of:) function by SE–0096.
.Type and .Protocol, which we propose to remove, see below.
.Self, which acts like an associatedtype.
.self, which will be reviewed in a separate proposal.
The tendency is to remove “magical” members: with this proposal there will only be .Self (does not count) and .self.

Also, .Type notation works like a generic type, and giving it generic syntax seems to be a good idea (unification).

Proposed solution

Remove P.Protocol type without a replacement. P.self will never return a P.Protocol.
Rename T.Type to Metatype<T>.
Rename type(of:) function from SE–0096 to metatype(of:).
Impact on existing code

This is a source-breaking change that can be automated by a migrator. All occurrences of T.Type and T.Protocol will be changed to Metatype<T>. All usages of type(of:) will be changed to metatype(of:)

Alternatives considered

Rename T.self to T.metatype. However, this can be proposed separately.
Use Type<T> instead of Metatype<T>. However, Metatype is more precise here.

···

--
Adrian Zubarev
Sent with Airmail


(Anton Zhilin) #20

Is noone interested? We are going to go for the second round of review with
this version of proposal.