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. :)
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
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution