What's the difference between metatype .Type
and .self
in Swift?
Do .self
and .Type
return a struct
?
I understand that .self
can be used to check with dynamicType
. How do you use .Type
?
“Self” as a Type in Swift This “Self” has an uppercase “S”, which is how you can tell it apart from the lowercase self. In Swift, Self refers to a type – usually the current type in the current context. Just as lowercase self can mean any current object, uppercase Self can mean just about any current type.
In Swift, there are two kinds of types: named types and compound types. A named type is a type that can be given a particular name when it's defined. Named types include classes, structures, enumerations, and protocols.
Type is the type and String. self is the value of a metatype. let intMetatype: Int. Type = Int.
In Swift self is a special property of an instance that holds the instance itself. Most of the times self appears in an initializer or method of a class, structure or enumeration. The motto favor clarity over brevity is a valuable strategy to follow.
Here is a quick example:
func printType<T>(of type: T.Type) { // or you could do "\(T.self)" directly and // replace `type` parameter with an underscore print("\(type)") } printType(of: Int.self) // this should print Swift.Int func printInstanceDescription<T>(of instance: T) { print("\(instance)") } printInstanceDescription(of: 42) // this should print 42
Let's say that each entity is represented by two things:
Type: # entitiy name #
Metatype: # entity name # .Type
A metatype type refers to the type of any type, including class types, structure types, enumeration types, and protocol types.
Source.
You can quickly notice that this is recursive and there can by types like (((T.Type).Type).Type)
and so on.
.Type
returns an instance of a metatype.
There are two ways we can get an instance of a metatype:
Call .self
on a concrete type like Int.self
which will create a static metatype instance Int.Type
.
Get the dynamic metatype instance from any instance through type(of: someInstance)
.
Dangerous area:
struct S {} protocol P {} print("\(type(of: S.self))") // S.Type print("\(type(of: S.Type.self))") // S.Type.Type print("\(type(of: P.self))") // P.Protocol print("\(type(of: P.Type.self))") // P.Type.Protocol
.Protocol
is yet another metatype which only exisits in context of protocols. That said, there is no way how we can express that we want only P.Type
. This prevents all generic algorithms to work with protocol metatypes and can lead to runtime crashes.
For more curious people:
The type(of:)
function is actually handled by the compiler because of the inconsistency .Protocol
creates.
// This implementation is never used, since calls to `Swift.type(of:)` are // resolved as a special case by the type checker. public func type<T, Metatype>(of value: T) -> Metatype { ... }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With