taylor swift taylor swift - 22 days ago 10
Swift Question

Idiomatic way to unwrap an integer string input

Sorry if this is a basic question, but I am learning Swift and I don’t understand how to unwrap inputs from

readLine()
.

For example, I would expect this

let n: Int = Int(readLine(strippingNewline: true) ?? -1)


to work, but it doesn’t. Nor does replacing the
-1
with a
"-1"
to match types.

let n: Int = Int(readLine(strippingNewline: true) ?? "-1")


What is the “right” way to do this then? Can someone explain exactly what Swift is doing when it unwraps optionals and uses them as arguments for a constructor like
Int
?

The whole concept of optionals is a bit foreign to me (a Python programmer); in Python you handle invalid input the “ghetto way”, putting out fires only after they happen:

try:
n = int(input())
except ValueError:
n = None


but I assume the paradigm in Swift is different.

Answer

There are two optionals at play here.

First, readLine(strippingNewline: true) is optional. It can return nil if there's no input recieved prior to the End of File (EOF) character being received. It must be unwrapped before being passed into Int()

Secondly, Int() is optional, because the String it was given may not be a valid string representation of a number.

Do not use -1 in Swift to represent "no value". This is called a sentinel value, and it's exactly what optionals are invented to prevent. How do you distinguish between a -1 meaning "no/invalid input", and a -1 meaning "the user's input was -1?

Here is how I would write this code:

guard let userInput = readLine(strippingNewline: true) else {
    // If we got to here, readLine(strippingNewLine:) returned nil
    fatalError("Received EOF before any input was given")
}

// If we got to here, then userInput is not nil

if let n = Int(userInput) {
    // If we got to here, then userInput contained a valid
    // String representation of an Int
    print("The user entered the Int \(n)")
}
else {
    // If we got to here, then userInput did not contain a
    // valid String representation of an Int.
    print("That is not a valid Int.")
}