Menu
Coddy logo textTech

Type Casting

Part of the Object Oriented Programming section of Coddy's Swift journey. Lesson 33 of 57.

is checks whether a value is of a given type, including subclasses and protocol conformances:

class Animal {}
class Dog: Animal {}
class Cat: Animal {}

let pets: [Animal] = [Dog(), Cat(), Dog()]
print(pets.filter { $0 is Dog }.count)
print(pets[1] is Animal)

Output:

2
true

as? tries to treat a value as a more specific type. It returns an optional: the value when the cast works, nil otherwise. Combine it with if let to use the specific type's members:

class Animal {}
class Dog: Animal {
    func fetch() -> String { "fetching" }
}
class Cat: Animal {}

for pet in [Dog(), Cat()] as [Animal] {
    if let dog = pet as? Dog {
        print(dog.fetch())
    } else {
        print("not a dog")
    }
}

Output:

fetching
not a dog

switch can match on types with case let x as Type, which handles several types in one place:

let values: [Any] = [42, "hello", 3.5, true]
for v in values {
    switch v {
    case let n as Int: print("int \(n)")
    case let s as String: print("text \(s)")
    case is Double: print("a double")
    default: print("something else")
    }
}

Output:

int 42
text hello
a double
something else

as! forces the cast and crashes the program when it fails, so use it only when the type is certain. Frequent casting is often a sign that a method belongs in the protocol or superclass instead:

let pet: Animal = Cat()
// let dog = pet as! Dog   // crash: Cat is not a Dog
if let dog = pet as? Dog { print(dog) }   // safe
challenge icon

Challenge

Easy

A settings file is read into [String: Any]. Complete describe(_:), which returns one line per key in alphabetical order: volume: number 7, name: text "Ada", dark: switch on/switch off, ratio: decimal 0.5, or x: unknown for any other type. Use a switch with case let ... as patterns.

The supplied code reads lines key=value and stores the value as Int, Double, Bool or String (in that order of attempts, and [String] for values with |), then prints each returned line.

Your code goes in Functions.swift. main.swift holds the supplied input/output code and cannot be edited.

Try it yourself

// Supplied input/output code: keep it as it is
var input: [String] = []
while let line = readLine() { input.append(line) }
var settings: [String: Any] = [:]
for line in input {
    let p = line.split(separator: "=", maxSplits: 1).map(String.init)
    let raw = p[1]
    if let n = Int(raw) { settings[p[0]] = n }
    else if let d = Double(raw) { settings[p[0]] = d }
    else if let b = Bool(raw) { settings[p[0]] = b }
    else if raw.contains("|") { settings[p[0]] = raw.split(separator: "|").map(String.init) }
    else { settings[p[0]] = raw }
}
for line in describe(settings) { print(line) }
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming

Practice on your own: Swift playground