I struggle whenever I read or have to write MyType.self. This means you’re referring to a type and not using it … there’s a more accurate description involving instance of meta types, I know, but thinking on those terms is even more of a stumbling block for me and I’m guessing many others.
What other syntax is used for referring to something vs using it? Keypaths. \MyType.foo refers to the foo field of MyType.
So it makes sense to me that referring to a type shouldn’t use the unique syntax MyType.self but maybe instead \MyType.
Is that syntax already used for something? I can’t remember as I rarely find myself using keypaths.
Posting here before I embarrass myself on Swift Aevolution ;^)
Which, incidentally, is kind of confusing for types that have an implicit self, like structs and classes. Not confusing in the sense of having ambiguous syntax technically, but logically so. Especially since there's Self which is the better analogy. So arguably it should be MyType.Self.
MyType.Self would be a type (as in, a thing you can put after a colon or as?), MyType.self is a value, the same way Objective-C had a -class method rather than a -Class method.
In the prior post on generics, I noted that Swift doesn't have an equivalent to the decltype type in C++. Swift does, however, have a function named type(of:), which produces the type of its argument. However, it's not producing a type, but a value representing the type, i.e., a metatype.
Metatypes in Swift are spelled with the .Type suffix, so if we have a type Point:
struct Point {
var x: Double
var y: Double
static var origin: Point = Point(x: 0, y: 0)
}
The metatype of Point has the type Point.Type. One can form a value of this type with the expression Point.self.
let pointType: Point.Type = Point.self
What can you do with a metatype? For one thing, you can access static methods and properties, or call an initializer of that type to produce a new value, like this:
let point = pointType.init(x: 0.0, y: 0.0)
let origin = pointType.origin
Technically, when you write Point(x: 0.0, y: 0.0), you're using syntactic sugar for PointType.self.init(x: 0.0, y: 0.0).
I think MyType.self makes fair sense. To be more direct I’d treat the hardcoded type name as a reference to the thing itself…
let a = MyType
But we don’t have that. To refer to the type thing itself as a variable you need to use the self accessor...
let a = MyType.self
I can kinda see how this confuses with self on an instance, but they are representing similar things: give me a handle to yourself. It’s just that with a type name the self accessor is the only way to get a reference to that thing while with an instance it feels like there’s two because you’re usually inside self.