struct S {
static let a = 123
var b: Bool { return type(of: self).a == 123 }
}
and I guess it is equivalent to this:
struct S {
static let a = 123
var b: Bool { return S.a == 123 }
}
?
Does this mean that type(of:) is not always "the dynamic type of a value" as the documentation says, but sometimes it is evaluated at compile time (to S / an imaginary Self).
Also, what's the status of making Self available for structs (instead of having to write the specific type name, S in this case)?
protocol A {
static var a: String { get }
}
extension A {
static var a: String { return "A" }
var x: String { return type(of: self).a }
}
class B: A {
class var a: String { return "B" }
var y: String { return type(of: self).a }
}
class C: B {
override class var a: String { return "C" }
var z: String { return type(of: self).a }
}
let c = C()
(c as A).x // "C"
(c as B).y // "C"
(c as C).z // "C"
It's implementation details whether it is evaluated at compile time.
In general type(of: self) returns a dynamic metatype which represents always the bottom type of the your type hierarchy. In other words the type which was initially initialized. Since value types have no subtypes type(of: self) is the same like the 'static metatype'. Self behaves similarly.
class A {}
class B : A {}
struct S {}
A.self // static metatype A.Type
B.self // static metatype B.Type
S.self // static metatype S.Type
let a = A()
let a_as_any: Any = a
let b = B()
let b_as_a: A = b
type(of: a) // dynamic metatype A.Type pointing to a static metatype A.Type
type(of: a_as_any) // dynamic metatype Any.Type pointing to a static matatype A.Type
type(of: b) // dynamic metatype B.Type pointing to a static metatype B.Type
type(of: b_as_a) // dynamic metatype A.Type pointing to a static metatype B.Type
type(of: b_as_a) as! B.Type // should be theoretically safe
In case of protocols it get's a little weird. For more information you can read this deferred proposal.
A side note, type(of:) function is due to this strange merged design of metatypes pure compiler magic.
Your explanation is correct but your terminology is a little off here. The static type of type(of: b_as_a) is A.Type. The dynamic value of type(of: b_as_a) is B.self.
"refer to the metatype" is the terminology that's incorrect.
Abstractly, outside of Swift, "metatype" means "the type of a type". Within the Swift compiler/runtime world, we say "foo is a metatype" the same way we say "foo is an array", as shorthand for "foo is an instance of a metatype". That means that values that represent types (such as A.self) could conceivably be called "metatype instances"…but we don't say "array instances"; we just say "arrays".
I don't understand your "subtype hierarchy". There is no "A.Type (dynamic)" that's a supertype of "A.Type (static)", and I don't know what you mean by "dynamic metatype". If anything, you've written out a static type hierarchy (of metatypes rather than instances), with no dynamic in it anywhere.
I think part of the confusion around A.self and metatypes is that currently in Swift we don't have a way to programmatically manipulate/inspect them, short of Mirroring. If/when Swift's ABI locks down enough that it becomes somewhat stable to mess around with, I'm wondering if we could propose a counterpart to Mirror that allows operations on the direct metatype instances.
Well by A.Type : A.Type I really mean something like a class is a superclass (supertype) of itself A : A. In other words a type of the metatype is a supertype of itself. However this is not fully true in Swift.
Calling them "static" and "dynamic" just doesn't make sense, because it has nothing to do with "compile time vs. run time" or "direct vs. indirect dispatch". There are "values that represent the metadata for a specific nominal" and "values that represent the type of another value", and yes, we conflated those for classes, structs, and enums. For protocols, you can see the difference between "the protocol's metadata" and "values with protocol type (existentials)".
(Tuples and functions don't really belong in the first category, though. Those are structural types and can basically only be types of values, not something with identity.)