66

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?

Victor Sigler
  • 22,039
  • 12
  • 83
  • 98
Boon
  • 37,606
  • 51
  • 186
  • 296
  • 1
    Some of the info at the bottom of this might be helpful: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html#//apple_ref/doc/uid/TP40014097-CH31-ID457 – mbottone Jul 15 '15 at 18:38
  • @Pops I read that before posting this question. – Boon Jul 15 '15 at 19:46
  • 2
    Might read this: http://www.apeth.com/swiftBook/ch04.html#_type_reference Note especially the summary at the end of the section. – matt Jul 15 '15 at 21:31
  • @matt Good stuff, thank you. – Boon Jul 15 '15 at 22:15
  • @Boon thanks, glad if it helps. I get confused too - that's why I put the summary at the end! – matt Jul 15 '15 at 22:22

5 Answers5

51

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 { ... }
ScottyBlades
  • 7,536
  • 2
  • 50
  • 60
DevAndArtist
  • 4,391
  • 1
  • 20
  • 45
  • 5
    You're welcome :) There is also a `.dynamicType`. This one is to get the last level type of your instance at runtime. Lets say you have this: `let instance : UIView = CustomUIView()` then you will call `instance.dynamicType` somewhere and then you'll get `CustomUIView` and not `UIView`. ;) – DevAndArtist Jul 15 '15 at 20:04
  • Is .Type return a class or a struct or both? – Boon Jul 15 '15 at 20:51
  • 1
    It doesn't matter if it's a struct, enum or class. It will return the type for that thing. If you have `struct A {}` then `A.self` will return `A`. – DevAndArtist Jul 15 '15 at 20:54
  • 1
    `.Type` is not magic, it says that you will pass/have a metatype for a specific type and not it's instance. `.self` is there to get this metatype. It's kinda hard to explain with all these type suffixes everywhere. :D – DevAndArtist Jul 15 '15 at 21:00
  • By compiler magic I mean Type is not really a thing we can see a definition of (like we can with Dictionary or Array) – Boon Jul 15 '15 at 22:16
  • I feel like the word 'meta' here is misleading. Replacing 'metatype' with 'typeName' in Apple's documentation will reduce the confusion – Honey Feb 07 '19 at 20:31
  • So basically you use `.Type` for parameters and `.self` for arguments? (https://stackoverflow.com/a/156787/865175) – Iulian Onofrei Oct 29 '19 at 15:58
39

Where is it used?

If you are writing/creating a function that accepts a type e.g. UIView.Type, not an instance e.g. UIView()then to you would write T.Type as the type of the parameter. What it expects as a parameter can be: String.self, CustomTableView.self, someOtherClass.self.

But why would a function ever need a type?

Normally a function which requires a type, is a function that instantiates objects for you. I can think of two good examples:

  1. register function from tableview
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell")

Notice that you passed CustomTableViewCell.self. If later on you try to dequeue a tableView of type CustomTableViewCell but didn't register CustomTableViewCell type then it would crash because the tableView hasn't dequeued/instantiated any tableviewcells of CustomTableViewCell type.

  1. decode function from JSONDecoder. Example is from the link
struct GroceryProduct: Codable {
    var name: String
    var points: Int
    var description: String?
}

let json = """
{
    "name": "Durian",
    "points": 600,
    "description": "A fruit with a distinctive scent."
}
""".data(using: .utf8)!

let decoder = JSONDecoder()
let product = try decoder.decode(GroceryProduct.self, from: json)

print(product.name)

Notice try decoder.decode(GroceryProduct.self, from: json). Because you passed GroceryProduct.self it knows that it needs to instantiate an object of type GroceryProduct. If it can't then it would throw an error. For more on JSONDecoder see this well written answer

  1. As an alternate workaround for where types are needed see the following question: Swift can't infer generic type when generic type is being passed through a parameter. The accepted answer offers an intersting alternative.

More about the internals and how it works:

.Type

The metatype of a class, structure, or enumeration type is the name of that type followed by .Type. The metatype of a protocol type—not the concrete type that conforms to the protocol at runtime—is the name of that protocol followed by .Protocol. For example, the metatype of the class type SomeClass is SomeClass.Type and the metatype of the protocol SomeProtocol is SomeProtocol.Protocol.

From Apple : metaType Type

Under the hood AnyClass is

typealias AnyClass = AnyObject.Type // which is why you see T.Type 

Basically where ever you see AnyClass, Any.Type, AnyObject.Type, its because it's in need of a type. A very very common place we see it is when we want to register a class for our tableView using register func.

func register(_ cellClass: Swift.AnyClass?, forCellReuseIdentifier identifier: String)

If you are confused as to what does 'Swift.' do then above, then see the comments from here

The above could have also been written as:

func register(_ cellClass: AnyObject.Type, forCellReuseIdentifier identifier: String)

.self

You can use the postfix self expression to access a type as a value. For example, SomeClass.self returns SomeClass itself, not an instance of SomeClass. And SomeProtocol.self returns SomeProtocol itself, not an instance of a type that conforms to SomeProtocol at runtime. You can use a type(of:) expression with an instance of a type to access that instance’s dynamic, runtime type as a value, as the following example shows:

From Apple : metaType Type


Playground code:

Easy example

struct Something {
    var x = 5
}

let a = Something()
type(of:a) == Something.self // true

Hard example

class BaseClass {
    class func printClassName() {
        print("BaseClass")
    }
}
class SubClass: BaseClass {
    override class func printClassName() {
        print("SubClass")
    }
}


let someInstance: BaseClass = SubClass()
/*                      |                |
                    compileTime       Runtime
                        |                | 
To extract, use:       .self          type(of)

  Check the runtime type of someInstance use `type(of:)`: */

print(type(of: someInstance) == SubClass.self) // True
print(type(of: someInstance) == BaseClass.self) // False

 /* Check the compile time type of someInstance use `is`: */

print(someInstance is SubClass) // True
print(someInstance is BaseClass) // True

I highly recommend to read Apple documentation on Types. Also see here

Honey
  • 24,125
  • 14
  • 123
  • 212
  • I'm not a strong swift programmer, but I guess `tableView.register(Class, forCellReuseIdentifier: "CustomTableViewCell") ` is what a novice programmer would try instead of `Class.self` to pass a type into a function? Why is `Class.self` needed when `Class` seems syntactically simpler? – Ben Butterworth Oct 25 '20 at 21:48
  • `Table.Type` is used for when a function expects a type, not an instance. `Table` is used when a function expects an instance of that type. Respectfully `Table.self` and `Table()` satisfy such functions expectations. These 4 distinct purposes hence you can’t do what you say – Honey Oct 26 '20 at 00:10
  • I understand why the metatype needs to be used in the function signature, but why does one have to pass as argument, `Table.self`, why not just `Table`, as it seems simpler and can also be possible. I don't see the purpose of the `type as a value` phenomenon. – Ben Butterworth Oct 26 '20 at 07:28
  • Oh, `Table` on its own would just signify a 'return type', rather than be usable as a value, so using `type as a value` **is** important. Thanks – Ben Butterworth Oct 26 '20 at 07:42
  • @BenButterworth my answer to your question is nothing but what I just said. If it helps [newacct's answer below](https://stackoverflow.com/a/31441486/5175709) also answers your question. It's merely how the compiler was designed to read – Honey Oct 26 '20 at 11:52
  • Yes, my question is about the *mere* compiler design: to rephrase, *why use Class.self* when you can design the compiler to work with `Class`, and my previous comment hopes to answer this. It seems like if swift had a smarter compiler it could be possible to use `Class` in place of `Class.Type` and `Class.self`, and it uses the syntax to determine which what you meant. – Ben Butterworth Oct 26 '20 at 11:58
  • I don't know. You should ask Swift designers – Honey Oct 26 '20 at 12:15
17

They appear in different places syntactically.

In a place syntactically where you have to specify a type, Something.Type is a valid type, corresponding to the type that is the metatype (which is metaclass for classes) of Something. Something.self is not a valid syntax for a type.

In a place syntactically where you have to write an expression, Something.self is a valid expression. It's an expression of type Something.Type, and the value is the thing ("class object" in the case of classes) that represents the type Something. Something.Type is not a valid expression syntax.

newacct
  • 110,405
  • 27
  • 152
  • 217
2

This was one of those topics that confused the hell out of me today.

I was writing a generic function:

func foo<T: Protocol>(ofType: T.Type) {
    T.bar()
}

And tried calling it as follows:

foo(ofType: ClassImplementingProtocol.Type) // Compiler error

Spent about 30 min researching why it wasn't working. Then I tried this:

foo(ofType: ClassImplementingProtocol.self) // Works

Turns out Xcode's code completion is very bad at showing the difference between meta types and types... From the code completion pop-up it looks like .self and .Type are the same thing:

enter image description here

But the "explain like im 5" of it is, when you have a method parameter of Class.Type, it is expecting an instance of Class.Type.

Class.self returns an instance of Class.Type, whereas Class.Type is referring to Class.Type...

Very unclear if you ask me.

Xaxxus
  • 370
  • 2
  • 12
0

Metatype .Type

Metatype is a type which allows you to access to parts of Class and Struct[About] type(not instance) like initializers class and static[About] properties and methods

let var1: String = HelloWorld
let var2: String.Type = HelloWorld.self

Some experiments:

class SomeClass {
    required init() { }
    
    class func foo1() { }
    static func foo2() { }
    
    func foo3() { }
}

class SomeSubClass: SomeClass { }
let a1: SomeClass = SomeClass()
let a2: SomeClass = a1
let a3: SomeClass = a1.self

SomeClass.self.foo1() //class func
SomeClass.foo1() //class func

//static. metatype by type(class name) <class_name/structure_name>.self
let c1: SomeClass.Type = SomeClass.self
//dynamic. metatype by instance
let c2: SomeClass.Type = type(of: a1)

//access to type's init, class, static throught Metatype
let d1: SomeClass = c1.self.init()
let d2: SomeClass = c1.init()

//call
c1.foo1() //class func
c1.foo2() //static func
//        c1.foo3() //instance func. Instance member 'foo3' cannot be used on type 'SomeClass'
//        c1.foo3(SomeClass()) //Expression resolves to an unused function

//Sub
// <class_name>.Type allows to save class and sunclass
var e1: SomeClass.Type = SomeClass.self //class
e1 = SomeSubClass.self //sub class

//Any.Type allows to save class and struct
var e2: Any.Type = SomeClass.self //class
e2 = String.self //struct

//AnyObject.Type allows to save only class
var e3: AnyObject.Type = SomeClass.self //class
e3 = NSString.self //class

get String

let typeString = "\(SomeType.Type)"

func register<T>(instance: T) {
    instanceString = String(describing: type(of: instance))
}
yoAlex5
  • 13,571
  • 5
  • 105
  • 98