Type Inference is a powerful capability that lets Swift automatically assign a type for a given variable/constant/property where a value is assigned but a type is not explicitly assigned. Swift infers the type of the variable/constant/property by looking at the value it was assigned.
Swift is a strongly-typed language — meaning, type of a variable/constant/property must be known at the time of declaration. However, it can assist you by inferring it if you provide a value. This makes the code cleaner and more compact to read. If the type is not explicitly mentioned, and if no value is assigned, Swift has no way of knowing the type of that variable - and that would be an error.
// Here name is assigned a string
// That means, Swift can infer the type of name to be String
let name = “Thomas Edison”
// Here the score is assigned an explicit type Int
// Hence the type of score will be Int
// This is not initialized yet - but must be given a value before it is used
var score: Int
// Swift knows length below is a variable, not a constant
// But no type has been assigned explicitly
// There is no value either, for Swift to infer the type
// Since Swift is a strongly-typed language, following would be an error
// Below isGameOver has an explicit type Bool
// It has been assigned a boolean literal false
// This assignment is not wrong in Swift
var isGameOver: Bool = false
// However, Swift can infer the type from false
// There is no need to specify type and assign a value
// Following is cleaner and shorter and is preferred
var isGameOver = false
So, as mentioned in the code above, the preferred way is to provide a value and let Swift get the type by inferring it. This works with initializer of particular type (classes, structs, enums) as well as when you are assigning the return value from a function or method.
// In the declaration below, the UIColor() initializer returns a variable of type UIColor
var greenColor = UIColor(color: green)
// So, Swift can figure out the type of greenColor
// No need to mention it specifically like the following:
// var greenColor: UIColor = UIColor(color: green)
// Above line, while not incorrect, makes it verbose
// Similarly it works with custom classes as well
let game = Game.sharedInstance()
let card = Card()
// Return values from a function/method
// If the isGameOver() method returns a boolean, then gameStatus is Bool
// If it returns, say, a value of some enum type, then gameStatus will be that type
// Swift can look at the return value of the func and assign the type
var gameStatus = isGameOver()
So, in essence, Swift is helping keep the code shorter and readable. This is also very useful in case of closures, where you can safely omit a few things to make the code more readable where Swift can figure out what those missing things are.
The type safety in Swift comes from the fact that Swift is a strongly typed language and there are no automatic implicit conversions between the values of different types.
First - strongly-typed means, every variable and constant must belong to a type and that type must be specified. The type is either explicitly specified in the declaration or more often a literal value is assigned to it and the type is skipped. From that value, the type is inferred.
Various cases of type inference are discussed above. In Swift, value of one type cannot be assigned to a variable of another type. In C, an int value can be assigned to a char variable.
// In C, following will print letter A
// 65 is the ASCII code for letter A
int aNum = 65;
aChar = aNum;
// Prints: A
int aNum2 = 20;
aFloat = aNum2;
// Prints: 20.000000
In Swift, assignments like above are just not possible; Cannot even assign Int values to a Double. This is because Int is struct; and Double is struct — and they are different types. Even they seem like related, the values are not implicitly converted.
var aNum = 65
var aStr: String
aStr = aNum
// Error - Can’t assign a value of type Int to type String
var aNum2: Int = 20
var aFloat: Float
aFloat = aNum2
// Error - value of type Int cannot be assigned to Float
Because of these reasons — every variable needing a type (explicitly or via inference) and rule against assigning value of one type to another — Swift is a very safe language. This type of problems are caught before hand - don’t have to wait until runtime.
As we have seen above, there is no implicit conversion done by Swift between any two types, however strongly they are related in a conceptual sense. However, we would come into lot of situations where we have an integer and that needs to be converted to Double, because some function we want to use takes Double values, not Int values.
For situations like this, the types in question provide initializers that do the conversion. For example, Double has initializers that take Int, Float, and even String and spit out a Double value. There is an exhaustive listing of initializers for Int, Double, Float that take various Int types (Int16, Int32, Int64, UInt16, UInt32, etc.) and provide the number type you are looking at.
var aNum: Int = 20
var aDouble: Double
aDouble = Double(aNum)
// This works. We are using a Double(_: Int) initializer
var aStr = “40.05”
var aDouble2: Double?
aDouble2 = Double(aStr)
// Here aStr has a legitimate number, but in string format
// That gets converted to a Double properly
In the above code, a String value is converted to Double by using the Double(_:String) initializer. However, here we have declared aDouble2 as an optional — question mark after type: Double?. This lets aDouble2 hold either a Double value or a nil. If aStr does not have legitimate Double value, then the initializer will return a nil value.
There are these explicit conversion options via initializers for the standard types, where needed (primarily for number types). If you need one custom type converted to another, you would need to provide initializers or methods/functions that accomplish this and return the value of type you want. Obviously, those two types need to be logically connected to be able to do that.
This discussion is not the same as type casting, which is discussed elsewhere. Type casting converts one type to another type in the same inheritance hierarchy. An instance a base class can be converted to an instance of derived class (if you know that instance is actually of derived class) by using the keyword ‘as’. You can also check the type with the keyword ‘is’.