June 15, 2021
Type casting in Swift 
admin

Created by Apple in 2014, Swift is a popular open-source language for building iOS applications that has garnered a strong community of developers and a wealth of third-party content.

Like almost every other programming language, Swift has its own rules and syntax. In this guide, we’ll take a look at type casting in Swift, a popular concept in modern object-oriented programming languages.

What are types in Swift?

A type is, in essence, the primitive equivalent of a class that is used to denote the kind of data stored in a variable. As each class differs from the others, so do the data types, allowing developers to distinguish variables according to what kind of data they hold. Classifying data types prevents type mismatch, which is a common error at compile time.

Types are irrelevant to a compiler. If data stored in a variable is eligible for the operations carried out later in the flow, processes will run accordingly.

However, if a type mismatch causes a break in the flow, you’ll see a compilation error. Even if a type mismatch does not explicitly break the flow, it may go unnoticed during the compilation process, leading to unexpected results when running a program.

Swift is a strongly-typed programming language. Every variable in Swift has a type associated with it, and once a type has been assigned to a variable, it cannot store data of any other type.

Weakly-typed languages are not as strict in this regard. For example, in languages like PHP and C, you can alter data types to a certain extent to gain more flexibility in your code.

What is type casting?

The constraints of using types force a language to lose a big chunk of its flexibility. Type casting provides a way to gain some flexibility back.

Not all class variables hold primitive data like integers and strings. Most of a modern application’s logic relies on custom objects that are made possible via classes. From now on, we’ll refer to primitive data types and classes by types.

Type casting is a programming paradigm used in most object-oriented languages that allows developers to treat an object of one type like that of another. While type casting may not make much sense at first, it helps to simplify many routines in modern applications.

Type casting does not change the object concerned. Instead, it changes the type used to describe the object. For example, you obviously can’t change the type of an object holding a string from string to integer because it wouldn’t make sense in real life to treat a sentence as a number.

For type casting to occur, the concerned object’s original type and the new type must be either subclasses or superclasses of one another. Let’s say a class called Vehicle has two subclasses, Car and Truck. You can cast an object of type Car to Vehicle, and vice-versa, or Truck to Vehicle, and vice-versa.

Now, let’s say there was another class called Ship, which had no relation to Truck, Car, or Vehicle. You would not be able to cast its objects to any of the types given above.

Upcasting

Upcasting is used to generalize a series of subclasses of a class by using a variable of the class itself. Let’s consider the example using Car, Truck, and Vehicle.

We mentioned earlier that Car or Truck could be type cast to Vehicle. An object of a subclass is type cast into an object of its superclass. Think of it as moving up in the class hierarchy.

Upcasting lets you store any kind of Vehicle in a reference of type Vehicle: Car, Truck, etc. We already know that these are descendants of the same class, Vehicle, and they are bound to have some similarities. Upcasting their objects to the Vehicle class uses this generalization, letting us run operations using loops and other routine paradigms.

Here’s an example of upcasting:

let truck:Truck = Vehicle(wheels:8)

In the code block above, you declare a reference named truck, which is of type Truck. Next, you initialize it with an instance of Vehicle, which has eight wheels. You can see that the type annotation for the reference variable and the object assigned to it are entirely different.

As mentioned earlier, we can perform this operation because Truck and Vehicle belong in the same class hierarchy. It is exactly like saying a truck is a vehicle, which is logically correct.

In the example above, the upcast was implicit. However, you can make it visible by running the following code:

let truck:Truck = Vehicle(wheels:8) as Truck

Later, we’ll cover implicit upcasting in greater detail.

Downcasting

Downcasting is the opposite of upcasting, and it refers to casting an object of a parent class type to an object of its children class. Downcasting is used to reconvert objects of a children class that were upcasted earlier to generalize.

Let’s say you own two cars and three trucks. If you store them in a shared array, the type inference will decide the type of the array as Vehicle, a common parent to both types.

If you try to get an item from the array, you will get an object of type Vehicle. To change it back to its original type, you will need to downcast it into a Truck or a Vehicle.

It is essential to understand that not all vehicles on the list will be cars, which may cause the downcast to fail in some cases. To solve this problem, we’ll use two types of downcasting operators, which we’ll cover later.

Horizontal type casting

Notice that Car and Truck share a common superclass, however, you can’t cast an object of type Car to Truck, or vice-versa. They are neither subclasses nor superclasses of one another. Therefore, horizontal casting is disabled, and you’ll get an error if you try to cast a Car into a Truck.

Type casting operators in Swift

To perform the operations described above, you’ll use the following operators:

as

The as operator is used to upcast objects. However, in most cases, upcasting is done implicitly, so you will not use as frequently.

To reiterate, here’s an example of upcasting Chair to Furniture:

let furniture:Furniture = Chair(legs: 4) as Furniture

as?

The as? operator is used for optional downcasting and is one of the two downcasting operators available in Swift. Use as? when you are unsure if an object can be downcasted successfully.

If you try to downcast an object from a different class hierarchy, your program returns a nil value upon encountering an error. To verify if the downcast was successful, you can put a simple check for nil.

You can use the as? operator with our Vehicle example:

let truckObject = vehiclesArray[0] as? Truck

You’re instructing the control to access the first object from the array, downcast it to a Truck, and store the result in the truckObject variable.

If the downcast was successful, you’ll find a Truck instance in truckObject. If it fails, truckObject will point to nil. You can then check for nil by running:

if truckObject != nil {
print(“The reference points to some value!”)
} else {
print(“The reference points to nil, and so the downcast was unsuccessful”)
}

as!

The as! operator is used for forced downcasting, and it returns an object only if the type cast operation is possible. If you attempt to downcast an object from a different class hierarchy, your program will encounter a fatal error.

Here’s how you can use the as! operator with our Vehicle example:

let carObject = vehiclesArray[1] as! Car

The line of code above is instructing the control to access the second object from the array, downcast it to a Truck, and store the result in the truckObject variable. If the downcast fails, the program crashes.

With these points in mind, you should use the as! operator only when you are sure that the object you are downcasting belongs to the class hierarchy, and the operation will be completed successfully.

You can also use the as! operator in situations where the code’s flow requires a break if the types mismatch, which indicates that there may be unexpected results in the intermediate calculations.

is

The is operator is used to check the type of an instance. The result of a type check using the is operator is of type Bool, which indicates whether the type matched or not, as seen in the code block below:

let car: Car = Car(wheels: 4)

if car is Car {
print(“It is a Car.”)
} else if car is Truck {
print(“It is a Truck.”)
}

The output is:

It is a Car.

You can also use the is operator to check for any implicit upcast. Let’s consider an example:

let car: Car = Vehicle(wheels: 4)

print(car is Car)
print(car is Truck)
print(car is Vehicle)

The output for the code above is:

true
false
true

The output indicates that the car reference is of type Car and the implicitly upcasted type Vehicle. Since horizontal casting is not possible, Car can never be of the type Truck.

Try it yourself

In this article, you learned about types and type casting in Swift and covered the various operators used to type cast objects.

Type casting is a concept that makes object-oriented programming very powerful and flexible. With the ability to move up and down the class hierarchy through upcasting and downcasting, you can make use of generalization as needed.

The key to retaining all of the information is to keep practicing. I hope you enjoyed the article. Happy coding!

 

The post Type casting in Swift  appeared first on LogRocket Blog.

Leave a Reply

Your email address will not be published. Required fields are marked *

Send