Guarding Against Bad Input

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

In the previous demo, you improved the solution to have the complexity to O(1) from O(n). You managed to calculate the sum of numbers between zero and one hundred million in an instant instead of 20 minutes.

In this part, you’ll learn a few things you can use in the next demo to cause your solution to crash or give wrong results.

The code you write shouldn’t assume that the input will follow the rules you thought of when you wrote it. Any function you write is going to be part of a larger program, and there might be bugs out there. You’d want to end the chain of wrong values because it might cause bigger problems.

On June 4, 1996, the rocket Arian 5 exploded 40 seconds after launch. A single line of code caused a bug that switched a number from a positive value to a negative value. The incorrect value caused a series of problems that resulted in the rocket’s explosion.

Bugs are almost unavoidable, no matter how good you are. What’s important is to not let the bug of an unexpected value become a wrong input to the next part of your system. Some bugs can cause your app to crash. This is also a poor experience for someone trying to use your app. Understanding how your code works allows you to prepare for unexpected possibilities.

Int has a strict range: The maximum value you can have in a 64-bit computer with this data type, represented in Int.max, equals 9_223_372_036_854_775_807. Remember from the previous lesson that different computers can have different maximum values. So Swift provides constants like Int.max that give the maximum value of an Int on the hardware running the code.

Nine quintillion is a huge number, and you might think that you’d never reach this value, but you can never know for sure.

Adding just one to this value causes a crash if you’re using Int. For situations where you need larger numbers, Float is the right choice.

9223372036854775807 + 1 // This will give an error on Playground

var floatValue: Float = 9223372036854775807
floatValue = floatValue * 100

print(floatValue)

floatValue can hold very large values, but it ignores the smaller digits to prioritize the larger ones. In this case, it’s storing the first seven digits from the left and the rest are zeroes. Try the same with a Double:

var doubleValue: Double = 9223372036854775807
doubleValue = doubleValue * 100

print(doubleValue)

Double has a higher precision than Float. It can store the values of the first 16 digits from the left. So your choice of data types can make a significant difference when you might be dealing with large numbers.

It’s important to understand that Float and Double sacrifice the digits on the right — such as units, tens, and hundreds — in favor of large numbers. Looking at the following code:

var floatValue: Float = 9223372036854775807
var floatValue2: Float = 9223372036854775807 + 1

if floatValue == floatValue2 {
  print("How is this possible?")
}

This if condition will give a value of true, although you can clearly see that those numbers aren’t equal. But Float completely ignores the unit and the final stored values became identical.

If you’re curious about the maximum number that Float and Double represent, they don’t have a .max constant. They have a .greatestFiniteMagnitude value.

Float.greatestFiniteMagnitude
Double.greatestFiniteMagnitude

Another key point — perhaps the most important for your function — is to ensure that the input you receive in your function matches your expectations.

When you implemented the Fibonacci sequence, you ensured that the index requested in the input was a positive number. If it wasn’t, you returned zero.

If one of your inputs must be smaller than the other, it’s best to ensure they are. If you use a while loop, for example, you might end up with a condition that never happens:

var minValue = 100
var maxValue = 0

while (minValue != maxValue) {
  doSomething()
  minValue += 1
}

The code assumes that minValue starts with a smaller value than maxValue. The earlier increases one by one until it reaches the value of the latter.

If they start with opposite values, the condition will never happen and your app will be stuck in this loop until it crashes when minValue reaches 9223372036854775807.

The last point to cover is simple yet occurs very frequently. Int values don’t hold fractions. Five divided two is 2.5. But if you’re dividing Int values and storing them in another Int, rounding will happen:

var intValue = 5
intValue = intValue / 2
print(intValue)

In this situation, intValue will have a value of 3. Int always rounds to the nearest full digit: It rounds up anything half or above and rounds down anything below half.

This can make a significant difference in the final result if you have division in your algorithm and you’re storing the values in an Int.

In the next demo, you’ll try different inputs that will crash your code or produce wrong results.

See forum comments
Download course materials from Github
Previous: Measuring Demo Next: Crashing Demo