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"
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 toT
, 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:
getTypeOfReferenceWithSpecialTypeCheckingSemantics
which injects the type constraint in the type checker constraint system.type(of:)
is handled here as an overload, becauseMetadata
isn't actually bound; the constraint solver here applies an effective type checking constraint which constrainsMetadata
to be the actual type ofvalue
. The key here is thattype(of:)
is written in this way so that it would be an overload, and handled here.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 turntype(of: <expr>)
into a DynamicTypeExpr, but this effectively madetype(of:)
a reserved name. It's a bit more principled to putSwift.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 ifSwift.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
How to Show an Alert from Another Class in Swift
How to Fix Error: This Class Is Not Key Value Coding-Compliant for the Key Tableview.'
Window Visible on All Spaces (Including Other Fullscreen Apps)
How to Share Both Image and Text Together in Swift
Swiftui - How to Use Oncommand with Nsmenuitem on MACos
How to Add Initializers in Extensions to Existing Uikit Classes Such as Uicolor
Difference Between String Interpolation and String Concatenation
Swiftui: How to Draw Filled and Stroked Shape
Healthkit Error: Missing Com.Apple.Developer.Healthkit Entitlement
Swift Tableview Cell Set Accessory Type
Sprite-Kit: Moving an Element in Circular Path
Converting String to Data in Swift 3.0