Type Safety in Swift
Swift implements type safety, which basically means that you can’t use a variable inappropriately for the terms of its type. In other words, according to the rules of type safety, you can divide by zero — that’s not a type error — but you can’t perform an arithmetic operation with a string unless you do some conversions first.
Type safety can be described in a language specification and is enforced in a development environment like Xcode; it can also be enforced with careful programming. That’s part of the problem: Without enforced type safety, it’s very easy to slip up and create unsafe code.
In many environments, unsafe code may fail the first time you run it — this is the best-case scenario. Unfortunately, the most common scenario is that the code fails at various times. Often its failure has to do with the memory your app has to work with, so the unsafe code may fail depending on what other apps or functions are running at the time.
Letting the development environment enforce type safety is the safest way of handling these problems. (Relying on the good intentions of people is, alas, not always the wisest choice.)
The Swift language specification describes its type safety as part of the language; the entire language specification is enforced by the compiler as well as by the Xcode development environment. In common usage, however, people often say things like “Swift enforces type safety.”
In fact, Swift only provides the specification; it’s Xcode and the LLVM compiler that do the enforcement. Nevertheless, unless there is a reason to make a distinction between the Swift specification and its implementation in Xcode and the compiler, this book refers in a general way to Swift.
Swift takes two approaches to enforcing type safety: tightening up coding standards and inferring types. It uses other approaches as well, but these are the major ones.
Tightening coding standards
There has long been a trade-off (some people would call it a battle) between the coding practices of strict and loose typing of variables. Strict typing is more trouble, and it can cause compile errors as the compiler objects to vaguely-typed variables. Loose typing is simpler to write and incurs fewer compiler errors, but it can cause more runtime errors and crashes.
Swift tightens coding standards. To a large extent, these standards consist of language limitations that prevent unsafe code. Here are some of the type safety measures that Swift puts in place and enforces:
Pointers: Pointers let you access memory directly, which can lead to all sorts of problems. The basic Objective-C syntax for accessing an instance of a class involves a pointer: This is not the case with Swift.
When you declare an instance of a class such as UIView in Objective-C, you do so with code such as UIView *myView. That asterisk indicates that you’re working with a pointer (this is plain old C syntax). If you are used to Objective-C, most of those asterisks are history for you. The exception is if you are mixing Objective-C and Swift.
Initialization: Variables must be initialized in Swift before use. There is no way to use uninitialized variables in Swift.
No nil: In other languages, nil is often used to provide a value that can be tested to see if an object exists. In Swift this is handled with optional types.
Memory management and overflow checking: Swift has inherited Objective-C’s features implemented with advanced compiler behaviors, such as Automatic Reference Counting (ARC).
Because Swift requires variables (and constants) to be initialized before being used, the compiler and runtime library always have a value for each variable. From this value, Swift can infer a type without your having to specify it. In other words, you can specify the type for any variable, but you don’t have to do so if that variable is initialized with a value from which Swift can infer the type.
Arrays and dictionaries in Swift must contain instances of the same type. Thus, when you create an array or dictionary, you must either explicitly specify its type or provide initial values so that Swift can infer the type of the array or dictionary. In either case, Swift can determine the type of the values in the array or dictionary.
When you are dealing with classes and subclasses, you may want to use an explicit type. If your array or dictionary is eventually going to contain instances of subclasses of a given class, you may initialize it with several of those subclasses.
For example, an array that will contain various instances of UIView subclasses can be initialized with one or more UILabel instances. However, there is no way Swift could infer UIView from instances that do not include all possible UIView subclasses. So if you’re aware that you’ll want to add (say) UIButton instances later on, you may prefer to explicitly type the array as UIView so all of the UIView subclass instances are welcome.