Skip to content
Theory · Variables and types · lesson 4 of 7

Type conversion

In the previous lesson, a type was the shape of a box. But sometimes a value sits in a box of one shape while you need it in another. Then you move it over, and in Swift you always do that explicitly, with a separate piece of code.

Here is a task from a shop: an item costs 2.5, and you take 3 of them. The count is a whole number, the price a fractional one. To multiply them, you first move the count into a box for fractional numbers:

SWIFT
let count = 3
let price = 2.5
let total = Double(count) * price
print(total)  // 7.5

Let's walk through the example line by line:

  1. count gets the type Int: the number 3 has no dot.
  2. price gets the type Double.
  3. Double(count) takes 3 from count and makes the fractional 3.0 out of it. Both factors are now Double, and 3.0 * 2.5 gives 7.5.
  4. print(total) prints 7.5.

What happens if you remove Double(…)?

SWIFT
print(count * price) // ✗
TEXT
error: binary operator '*' cannot be applied to operands of type 'Int' and 'Double'

The * sign can multiply an Int by an Int and a Double by a Double, but not an Int by a Double. Swift does not turn one into the other on its own, even when that looks safe.

Interviewers like to ask: "Does Swift convert number types implicitly?" The answer is no. Values of different number types do not mix in one operation until one of them is converted explicitly.

Explicit conversion

A type conversion is written as the name of the target type with the value in parentheses. The code Double(count) has two parts:

  • Double — the type the value is moved into;
  • (count) — the value being moved.

The result is a new value of the target type. count itself does not change and stays an Int.

Three directions

From Int to Double

Double(…) makes a fractional number out of a whole one, and nothing is lost: 3 becomes 3.0. You pick this direction when a fractional number takes part in the calculation, like the price in the example above.

From Double to Int

A box for whole numbers has no room for a fractional part. Int(…) drops it rather than rounding. A negative number loses its fractional part the same way, so the result ends up closer to zero:

SWIFT
let height = 2.9
let temperature = -2.9
print(Int(height), Int(temperature))  // 2 -2
  1. Int(height) cuts the fractional part off 2.9 and gives 2, not 3.
  2. Int(temperature) cuts the fractional part off -2.9 and gives -2, not -3.

Here the box picture stops working. Something that did not fit into a box stays next to it, whole. But the fractional part is gone for good after Int(…), and Swift warns you neither when compiling nor when running.

From a number to a string

String(…) turns a number into text: String(count) gives the string "3", and String(price) the string "2.5". A number and a string print the same, but to the program they are different things. You calculate with a number, while text can be attached to other text: "Count: " + String(count) gives Count: 3.

Numbers written in code

A number written right in the code gets its type from where it stands. In let count = 3 it becomes an Int. But in print(3 * 2.5) it stands next to a fractional number, so Swift makes 3 fractional right away, and the line prints 7.5. The constant count has no such freedom: its type Int was picked when it was declared.

Common mistake

The conversion was wrapped around the whole multiplication:

SWIFT
print(Double(count * price)) // ✗
TEXT
error: binary operator '*' cannot be applied to operands of type 'Int' and 'Double'

The compiler first checks what is inside the parentheses: count * price. That is still an Int and a Double, and * cannot multiply them by each other. So the program does not compile, and the Double(…) outside does not help. Convert the value count itself: Double(count) * price.

Key points

  • Swift does not convert types on its own: an Int and a Double do not mix in one operation.
  • A conversion is written as the type's name with the value in parentheses: Double(count), and count itself stays an Int.
  • Int(…) drops the fractional part rather than rounding: Int(2.9) is 2, and Int(-2.9) is -2.
  • String(…) turns a number into text that can be attached to other text.