Swift - what's the difference between metatype .Type and .self?
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 likeInt.self
which will create a
static metatype instanceInt.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 { ... }
Swift metatype (Type, self)
No, cls
and cls2
are different things. The easiest way to understand the difference will be to extend your example like this:
class SomeClass {
class func doIt() {
print("I'm a class method. I belong to my type.")
}
func doItOnlyIfInstanceOfThisType() {
print("I'm a instance method. I belong to my type instance.")
}
}
And now let's take your cls
:
let cls : SomeClass.Type = SomeClass.self
cls.doIt()
That will print I'm a class method. I belong to my type.
. But you cannot invoke this:
cls.doItOnlyIfInstanceOfThisType() // causes a compilation error, PRO TIP: actually you can use this method as a func property, but I'll add the explanation for this later
Let's take your cls2
. The only visible method of it is doItOnlyIfInstanceOfThisType
because it's an instance method (of this type).
let cls2 : SomeClass = SomeClass()
cls2.doItOnlyIfInstanceOfThisType()
So the difference between them is that cls
is a type and cls2
is an instance of this type.
A little bit more knowledge about why SomeClass.self and SomeClass()?
The type of a class also exists in memory (it has for example its own methods), as a singleton representing the Type (not an instance of this type - that's something different).
If you call self
on a Type like this SomeClass.self
you will get a singleton instance representing the SomeClass
Type.
SomeClass()
invokes the init()
method of SomeClass
, a constructor that creates an instance of SomeClass
.
PRO Tip
You can manipulate a Type instance function (like closures/blocks in ObjC). It's a generated class method. But you must pass an instance of the type that you take this method from as an argument, like this:
let myFunc :()->() = cls.doItOnlyIfInstanceOfThisType(cls2)
myFunc()
Using type as a value, why is the self keyword required here?
Self-answering, with help of comments, I was able to find out the reason:
Using .self
after the type name is called Postfix Self Expression:
A postfix self expression consists of an expression or the name of a
type, immediately followed by.self
. It has the following forms:expression.self
type.self
The first form evaluates to the value of the expression. For example,
x.self
evaluates tox
.The second form evaluates to the value of the type. Use this form to access a type as a value. For example, because SomeClass.self evaluates to the SomeClass type itself, you can pass it to a function or method that accepts a type-level argument.
Thus, the .self
keyword is required to consider the type as a value capable of being passed as an argument to functions.
Something.self vs self.something in Swift
Consider code like
JSONDecoder().decode(what, from: myJSONData)
What goes where I have what
? We have to tell the decoder what type of thing to expect to decode. Basically, what
is the name of a type — the name of a class, struct, or enum that conforms to Decodable.
But how to say the name of a type? Let's suppose that the type of thing you expect to decode is String. Then what do you say here?
JSONDecoder().decode(String, from: myJSONData) // error
No, you can't just say the name of a type out of the blue like that. This is how you do it:
JSONDecoder().decode(String.self, from: myJSONData)
What you're really passing here when you say String.self
is the metatype for String. And this example is exactly what it's for, i.e. when you need to pass a type as a parameter.
The declaration of this method signals this by using .Type
:
func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable
The expression T.Type
tells you that what you pass when you call this method should be Something.self
.
Swift leave out .self to invoke a function which needs metatype?
I also ask it in apple official forum, and get an answer there:
This is a famous undocumented feature of Swift, since 1.0 (or former > betas, which I cannot confirm).
When calling a method or function with single type argument, you can omit > .self .
I guess this feature is included into Swift to make sizeof-like functions > neat, but not sure.
https://forums.developer.apple.com/thread/24980
what is T.Type in swift
T.Type
is used in parameters and constraints to mean "the type of the thing itself, not an instance of the thing".For example:
class Example {
static var staticVar: String { return "Foo" }
var instanceVar: String { return "Bar" }
}
func printVar(from example: Example) {
print(example.instanceVar) // "Bar"
print(example.staticVar) // Doesn't compile, _Instances_ of Example don't have the property "staticVar"
}
func printVar(from example: Example.Type) {
print(example.instanceVar) // Doesn't compile, the _Type_ Example doesn't have the property "instanceVar"
print(example.staticVar) // prints "Foo"
}You get a reference to a Type's
.Type
(the Type object itself) at runtime by callingTheType.self
. The syntaxTheType.Type
is used in type declarations and type signatures only to indicate to the compiler the instance vs. type distinction. You can't actually get a reference to, for example,Int
's type at runtime or in your function implementations by callingInt.Type
. You would callInt.self
In the example code
var someValue: Int
, the specific notationidentifier: Type
(in this case,someValue: Int
) means that someValue will be an instance of Int. If you wanted someValue to be a reference to the actual type Int, you would writevar someValue: Int.Type = Int.self
Remember that the.Type
notation is only used when declaring types and type signatures to the compiler, and the.self
property is used in actual code to retrieve a reference to the type object itself at execution time.The reason why
JSONDecoder().decode
requires a parameter ofT.Type
(whereT
conforms toDecodable
) is because any type conforming toDecodable
has an initializerinit(from decoder: Decoder)
. Thedecode
method will need to call this init method on a type that conforms toDecodable
, not on an instance of a type that conforms toDecodable
. For example:var someString: String = ""
someString.init(describing: 5) // Not possible, doesn't compile. Can't call an initializer on an _instance_ of String
var someStringType: String.Type = String.self
someStringType.init(describing: 5) // Iniitializes a String instance "5"
Swift - switch on metatypes
Solution:
switch type {
case is [String].Type :
return "storageKey"
default:
return "nothing"
}
What is self used for in Swift?
You will also use self a lot when creating your extensions, example:
extension Int {
func square() -> Int {
return self * self
}
// note: when adding mutating in front of it we don't need to specify the return type
// and instead of "return " whatever
// we have to use "self = " whatever
mutating func squareMe() {
self = self * self
}
}
let x = 3
let y = x.square()
println(x) // 3
printlx(y) // 9
now lets say you want to change the var result itself
you have to use the mutating func to make change itself
var z = 3
println(z) // 3
now lets mutate it
z.squareMe()
println(z) // 9
// now lets see another example using strings :
extension String {
func x(times:Int) -> String {
var result = ""
if times > 0 {
for index in 1...times{
result += self
}
return result
}
return ""
}
// note: when adding mutating in front of it we don't need to specify the return type
// and instead of "return " whatever
// we have to use "self = " whatever
mutating func replicateMe(times:Int){
if times > 1 {
let myString = self
for index in 1...times-1{
self = self + myString
}
} else {
if times != 1 {
self = ""
}
}
}
}
var myString1 = "Abc"
let myString2 = myString1.x(2)
println(myString1) // "Abc"
println(myString2) // "AbcAbc"
now lets change myString1
myString1.replicateMe(3)
println(myString1) // "AbcAbcAbc"
Related Topics
Delete Folder With Contents from Firebase Storage
How to Disable Pasting in a Textfield in Swift
How to Load Url in Uiwebview in Swift
Sharing Userdefaults Between Extensions
Passing Lists from One Function to Another in Swift
How to Do a Swift For-In Loop With a Step
Ios 11 Custom Navbar Goes Under Status Bar
Property Initializers Run Before 'Self' Is Available
What Happened to the Uiview() Constructor in Swift 3.0
Usb Connection Delegate on Swift
Swipe-Able Table View Cell in iOS 9
How to Pass Multiple Enum Values as a Function Parameter
Swift Alamofire: How to Get the Http Response Status Code
Difference Between Flatmap and Compactmap in Swift