What Is T.Type in Swift

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 calling TheType.self. The syntax TheType.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 calling Int.Type. You would call Int.self

  • In the example code var someValue: Int, the specific notation identifier: 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 write var 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 of T.Type (where T conforms to Decodable) is because any type conforming to Decodable has an initializer init(from decoder: Decoder). The decode method will need to call this init method on a type that conforms to Decodable, not on an instance of a type that conforms to Decodable. 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"

What is T.self in Swift5?

I see that this question was answered in comments, but I felt it was worth an actual answer for people who are new to Swift trying to understand generics.

To answer the question, let's look at what T is, which is defined in the function's signature

func load<T: Decodable>(_ filename: String) -> T

This says that the generic function load(_:String) -> T returns some type T that conforms to Decodable, so T is a generic way of referring to the type of the return value, where that type will be determined from the context of the call site, specifically, by the type of whatever is receiving the returned value.

The line being asked about is

return try decoder.decode(T.self, from: data)

Here T.self is a way of referring to the type, T, itself. If you look at the function signature for decode you'll find it looks something like this:

func decode<T: Decodable>(_ type: T.Type, from data: Data) throws -> T

Note that it says T.Type for the type of the parameter, type. That means that the parameter type will hold the type T rather than a value of type T. This is Swift's way of differentiating between specifying that a variable is a value of a type vs its value being the type itself. This can be a little confusing at first, but it makes sense once you get your head around generics.

Because Swift is a strongly typed language, where types are defined at compile-time, decode needs to know the type of the thing its attempting to decode. In a typeless language, like JavaScript or Python, this isn't necessary. In those languages, objects are basically dictionaries, so it can always decode a dictionary (or an array, or one of a small set of primitive types). In Swift, struct and class are not just syntactic sugar for a dictionary. They are more like C-style struct - a bundle of binary data with a specific memory layout determined by the type. In order to decode properly, decode has to know what it's decoding, and most often, how to tell that thing to decode itself via its init(from: Decoder) throws method (which may have been synthesized by the compiler). Does it call NSImage.init(from: Decoder), or String.init(from: Decoder), etc... ?

If you're familiar with the way run-time polymorphism is implemented in OOP, providing the type, even generically, provides a means of obtaining the type's protocol witness table - which is sort of the protocol equivalent of the "vtable" that classes use for runtime dynamic dispatch for virtual methods. So it let's it do something analogous to calling a virtual method in OOP, except often it can figure it out at compile-time, and it can work for both value types and reference types. Understanding how his works also gives some insight into different but related issues like why you get different polymorphic behavior for the required methods declared directly in a protocol than for those declared only in a protocol extension (basically the ones declared in the protocol directly are in the witness table, so they can be dynamically dispatched, whereas the ones only in the extension aren't in the witness table, so any type-specific implementations are lost, and instead only the implementation in the protocol's extension can be called).

The following function uses this to print the type of its parameter (there are better ways of doing this, but this illustrates the roles of T.Type and T.self):

func foo<T>(_ value: T)
{
let typeOfValue: T.Type = T.self
print("The value, \(value), is of type, \(typeOfValue).")
}

Generics call with Type T in Swift

I think it is a bug.

You can work around it by making the class a sub-class of NSObject or mark constructor of base class with @required

import Cocoa

class A : NSObject {
init() { }
}
class B : A {}
class C : A {}

func Create<T:NSObject> () -> T {
return T()
}

println(Create() as A)
println(Create() as B)
println(Create() as C)

//<_TtC11lldb_expr_01A: 0x7f85ab717bc0>
//<_TtC11lldb_expr_01B: 0x7f85ab451e00>
//<_TtC11lldb_expr_01C: 0x7f85ab509160>

class D {
@required init() { }
}

class E : D {
init() { }
}

class F : D {
init() { }
}

func Create2<T:D> () -> T {
return T()
}

println(Create2() as D)
println(Create2() as E)
println(Create2() as F)

//C11lldb_expr_01D (has 0 children)
//C11lldb_expr_01E (has 1 child)
//C11lldb_expr_01F (has 1 child)

Not sure why @required solve the problem. But this is the reference

required

Apply this attribute to a designated or convenience
initializer of a class to indicate that every subclass must implement
that initializer.

Required designated initializers must be implemented explicitly.
Required convenience initializers can be either implemented explicitly
or inherited when the subclass directly implements all of the
superclass’s designated initializers (or when the subclass overrides
the designated initializers with convenience initializers).

(type: T.Type) makes generic method work whereas without it T cannot be inferred

If you don’t want to pass in the type, you can do something like this instead

let modelableExtended = ModelableExtended()
let result: [SomeType]? = modelableExtended.testFetch()
print(result)

At some point you have to say what T is by either passing in some parameter that refers to it or by assigning the result.

Generics are a compile-time feature. Perhaps you are thinking that they are like Any or AnyObject where you never have to say the type and then you can find out at runtime what you actually have. This isn’t how generics work.

A generic let’s you write code that can work with a lot of different types, but the code that actually runs is using a specific type that was inferred from its context. If it cannot be inferred, then the code will not compile and never be run.

Difference between `func T: Type ` and `func T (..) where T: Type`?

There is no difference, and I'm not aware of a convention.

Personally, prefer the first option, unless it makes the rest of the line have to line-break, in which case I use the second option instead.

Why does type(of:) return Metatype, rather than T.Type?

tl;dr: The behavior of type(of:) depends on whether T is existential or concrete, and the type system can't effectively reflect the actual return type syntactically, so it's handled directly in the type checking system. Metatype is specifically not bound in code to be the same as T so that the effective behavior can be specialized. Metatype and T are not necessarily related.


type(of:) is special in that its behavior differs depending on the type passed into it. Specifically, it has special behavior for existential types by being able to reach through the existential box to get the underlying type of the value passed in. For example:

func myType<T>(of value: T) -> T.Type {
return T.self
}

protocol Foo {}
struct X: Foo {}

let x = X()
print(type(of: x), "vs.", myType(of: x)) // => X vs. X

let f: Foo = X()
print(type(of: f), "vs.", myType(of: f)) // => X vs. Foo

When given an existential type like Foo, a return type of T.Type could only return the metatype of the existential itself (i.e. Foo.self), as opposed to the metatype of the value inside of the existential container (X.self). So instead of returning T.Type, type(of:) returns an unrelated type Metadata which is bound to the correct type in the type checker itself. This is the edge case you were looking for:

My guess is that there is some edge case where type(of:) will return a completely unrelated type to T, but I have no idea what that is.

If you look in lib/Sema/TypeChecker.h, you can see some special semantics declarations for several stdlib function types:

/// Special-case type checking semantics for certain declarations.
enum class DeclTypeCheckingSemantics {
/// A normal declaration.
Normal,

/// The type(of:) declaration, which performs a "dynamic type" operation,
/// with different behavior for existential and non-existential arguments.
TypeOf,

/// The withoutActuallyEscaping(_:do:) declaration, which makes a nonescaping
/// closure temporarily escapable.
WithoutActuallyEscaping,

/// The _openExistential(_:do:) declaration, which extracts the value inside
/// an existential and passes it as a value of its own dynamic type.
OpenExistential,
};

The key one here is TypeOf, which is indeed returned for functions with the @_semantics("typechecker.type(of:)") attribute you noted. (You can see how that attribute is checked in TypeChecker::getDeclTypeCheckingSemantics)

If you go looking for usages of TypeOf, there are two key locations in type-checking:

  1. getTypeOfReferenceWithSpecialTypeCheckingSemantics which injects the type constraint in the type checker constraint system. type(of:) is handled here as an overload, because Metadata isn't actually bound; the constraint solver here applies an effective type checking constraint which constrains Metadata to be the actual type of value. The key here is that type(of:) is written in this way so that it would be an overload, and handled here.
  2. ExprRewriter::finishApply which performs the actual expression rewriting in the AST to replace the return type with the effective actual type of the value

From (1):

// Proceed with a "DynamicType" operation. This produces an existential
// metatype from existentials, or a concrete metatype from non-
// existentials (as seen from the current abstraction level), which can't
// be expressed in the type system currently.

Pulling back some history — this was implemented back in commit 1889fde2284916e2c368c9c7cc87906adae9155b. The commit message from Joe is illuminating:

Resolve type(of:) by overload resolution rather than parse hackery.

type(of:) has behavior whose type isn't directly representable in Swift's type system, since it produces both concrete and existential metatypes. In Swift 3 we put in a parser hack to turn type(of: <expr>) into a DynamicTypeExpr, but this effectively made type(of:) a reserved name. It's a bit more principled to put Swift.type(of:) on the same level as other declarations, even with its special-case type system behavior, and we can do this by special-casing the type system we produce during overload resolution if Swift.type(of:) shows up in an overload set. This also lays groundwork for handling other declarations we want to ostensibly behave like normal declarations but with otherwise inexpressible types, viz. withoutActuallyEscaping from SE-0110.

Since then, as we can see from WithoutActuallyEscaping and OpenExistential, other special functions have been rewritten to take advantage of this.

Set type of generic T return in swift

The compiler needs some context to infer the type T. In a
variable assignment, this can be done with a type annotation or a cast:

let foo: Bool = myGenericFunction()
let bar = myGenericFunction() as Bool

If anotherFunction takes a Bool parameter then

anotherFunction(myGenericFunction())

just works, T is then inferred from the parameter type.

If anotherFunction takes a generic parameter then the
cast works again:

anotherFunction(myGenericFunction() as Bool)

A different approach would be to pass the type as an argument
instead:

func myGenericFunction<T>(_ type: T.Type) -> T { ... }

let foo = myGenericFunction(Bool.self)
anotherFunction(myGenericFunction(Bool.self))

Swift, use generic property with different specific types - Reference to generic type requires arguments in

You can specify a protocol for providing Stage types like so:

protocol StageProvider {

associatedtype T: Stage

func getType() -> T.Type

}

Then make your SomethingThatKnowsAboutTheStages or any other one conform this protocol:

class SomethingThatKnowsAboutTheStages: StageProvider {

typealias T = SecondStage

func getType() -> T.Type {
SecondStage.self
}

}

Add an initializer for your FooBarController:

class FooBarController<StageType: Stage>: UIViewController {

convenience init(stage: StageType.Type) {
self.init()
}

}

And finally use all these:

func fooBarScreen<T: StageProvider>(boop: T) {
let controller = FooBarController(stage: boop.getType())
}


Related Topics



Leave a reply



Submit