- Who Is This For?
- Basic Philosophies
- Swift Language Usage
- What This Presentation Covers
- Some Basics
- Main Characteristics
- More Phun Phacts
- Why I Love Swift
- Compiled, but Looks Like A Scripted Language
- Protocols (AKA “Interfaces”)
- Collections and Ranges
- Many Rabbit-Holes to Explore
This presentation is designed to be a relatively jargon-free presentation, and deliberately eschews the inclusion of sample code. The accompanying playgrounds will contain plenty of code, but we want to keep it out of the slides.
Who Is This For?
- Novice-to-Experienced Software Developers Unfamiliar With Swift
- People Curious About Swift, With Some Software Development Skills
The presentation is designed for folks who are familiar with basic modern software engineering techniques, but they don’t have to be “expert.” There will be a few references to some modern programming techniques and paradigms, but I will keep that to a minimum.
Swift was designed with a few basic drivers and philosophies.
It was designed to replace Objective-C, which was the original Apple development language.
Objective-C was much safer than the “original” C, but it is still a language that can get you into trouble. It has a lot of direct memory and process access, and can leak memory fairly easily. It doesn’t have much in the way of “guardrails.” Things like ARC (Automatic Reference Counting) are sort of a “kludge” that was applied over Objective-C.
Swift was designed to be much safer than C. It enforces a number of structural imperatives, and handles a lot of things that you used to have to do yourself in C.
Swift encourages the use of interfaces (which Swift calls “protocols”) over the use of traditional object-oriented inheritance hierarchies. Protocols tend to be much “shallower and lighter” than inheritance, and are used in a “mixin” fashion.
This can be both really good, or really bad; depending on how you implement and use them. Mixin programming is something that had a rather chequered past, with C++. Protocols don’t have the worst of those problems (the “diamond of death”), but they do have other issues; which aren’t for this presentation.
- Encourages Use of Value Semantics Wherever Possible
Swift tries to get the programmer to use value semantics as much as possible. This reduces the kinds of hard-to-find bugs that can happen when something that you SWORE wasn’t being referenced was, in fact, being referenced.
Value Semantics means that we copy data, as opposed to reference it.
In reality, a lot of what happens “under the hood” in Swift maintains references until a change to the data occurs, but we don’t have to worry about that, at the code level.
Additionally, value instances tend to be safer in multi-threaded environments than referenced instances. Thread safety is a big deal, and thread problems can be rather difficult to analyze and fix.
- Encourages Use of Constants Wherever Possible
Swift forces you to declare a property/variable as either “let” or “var”. “Let” means that it is a constant value, and won’t be changed. “Var” means that it can be changed after definition. The reason for this, is because the compiler can make “smarter” decisions, in regards to optimization, if it knows that the value won’t be changed after declaration. As a result, it encourages you to use “let” wherever possible.
- Affords Basic Functional Programming (FP) Techniques
Functional Programming is a methodology that mimics mathematical operations in code. Functions are treated as ‘first class citizens,” and can be handled as variables. Also, loops are not used directly. Closures (lambda functions, or blocks) and function properties are common.
Swift was designed to be usable as a Functional Programming language. It is not a “pure” FP language, but it uses many FP techniques and structures.
By the way, the only acronym that we’ll use here, will be “FP.” That’s because it’s a lot shorter than “Functional Programming.”
- Affords Creation of Simple Reusable Code Bases
- Makes Generics Completely “Mainstream”
Swift handles generics very well. It will make generics completely “invisible,” if there is no need to mention them, so you use generics all the time, without knowing it.
Swift is a very new language. As of the writing of this presentation, it is barely five years old.
- Created by Apple as their New System and Application Development Language
Swift was developed by Apple to replace Objective-C as their principal internal and external systems development language. Objective-C will still be around for some time, but Apple is dedicating all new development to Swift.
Apple makes Swift available as their supported application development language, supplying a rich API to their Cocoa infrastructure; in some cases, improving the way it works, over the Objective-C version of the same API (for example, we don’t need to worry about things like
- Designed by Chris Lattner; the Original Author of the LLVM Compiler Tools
Chris Lattner was the principal author of LLVM; the compiler toolchain that has pretty much revolutionized the way that new development languages are created.
- Development Started in 2010
While working at Apple in their development tools division, Chris Lattner vastly improved Objective-C, then started work on Swift in 2010, as a classified project. Swift was very secret. When it was announced, many at Apple were surprised.
- Announced at the June 2014 Apple Worldwide Developer Conference (WWDC)
At the 2014 World Wide Developer Conference (WWDC), Apple introduced the Swift Programming Language. It was still in late beta, and could not [yet] be integrated into released applications.
- First Apps Available As of September 2014 (Swift Version 1.0)
- ABI-Stable Version Available as Swift Version 5, as of March, 2019
As of late March, 2019, Swift (version 5) has become “ABI Stable.” “ABI” stands for “Application Binary Interface,” which refers to the functionality intrinsic to the language/operating system/runtime environment. That means that its standard library and the Foundation library are now built into the operating system (iOS >= 12.2, macOS >= 10.14.4, watchOS >= 5.2 and tvOS >= 12.2).
This is a major milestone for the language, as it is now “officially baked into” the operating system for all Apple devices.
It also means that this isn’t some new “fly by night” LLVM language du jour. It’s the principal development language of the world’s first trillion-dollar corporation; running billions of devices worldwide. It’s got legs.
Swift Language Usage
Swift is a very deep language, but it can be completely appropriate for full app development at a very high level.
Most Swift developers currently use probably less than half of Swift’s abilities. That will grow as the language matures.
Advanced Swift programmers can take advantage of some of its more intricate features, like higher-order functions, reflection, functional programming support, and focused extensions and protocols.
As of today, I suspect that the only people that fully utilize 100% of Swift’s capabilities are probably Apple employees; working in the Language team.
What This Presentation Covers
This is what we’ll be covering.
It’s not even scratching the surface of Swift.
Swift may offer Java programmers some comforting things.
It’s a C-based language, like Java, with braces establishing context, and linefeeds establishing new commands (you can still use semicolons, but they are not required).
- No Header Files; Only .swift (Implementation) Files
There are no header files; only implementation files (.swift).
- Can Have Multiple Classes/Structs/Enums/Protocols in a File
You can have multiple classes, structs and other language features in a source file. Programming convention still recommends you have one file per class; but it is not required by the language.
- Standard C-Style Comments (/*…*/, //)
Comments are exactly the same as in C or Java.
- Compiled and Linked, Using LLVM as the Target Compiler/Linker
It is a fully-compiled and linked language, unlike Java. It uses LLVM to perform the secondary optimization, compiling and integration into deliverable binary form. Everything is resolved at runtime.
- Linkage Applies Throughout the Module –Import Modules, Not Files
Like Java, it establishes the concept of a “module namespace.” You make implementation files part of a module, and their interface is (generally) exposed throughout the module (There are ways to mitigate this, but they are not commonly used). This differs from headers, like Objective-C uses. However, you do need to import modules in files that reference them.
Swift’s standard library is absolutely required (and built in) as an essential runtime component of the language. The Foundation Library adds some basic fundamentals to the language that are more focused on implementation in Cocoa (Apple’s frameworks). If you are writing Apple software, then Foundation is required to use some of the standard Apple data structures (like dates and Objective-C classes).
Like Objective-C, Swift has a single inheritance class model, with true polymorphism. Classes and structs can also be functionally extended (more on that, later).
- Strongly-Typed with Generics, and Forces Constant/Variable Declaration
Swift is very type-safe. It requires all types to be established at compile time.
You don’t have things like a variable starting off as a String, then becoming an Int, later on. Once a String; always a String.
There are a few “typeless types,” but they generally need to be cast, in order to be used.
Using optionals, it is possible to do “safe casting” of types at runtime.
- Advanced Protocol (Interface) Support
Swift has a very powerful protocol system (interfaces, in Java and other languages).
With protocol extensions that allow default functionality, you have something that looks a lot like multiple inheritance and abstract classes.
Swift has built-in structural support for many Functional Programming concepts. You can implement functors and monads a number of ways in Swift, and composition is built in.
- No Macros
There are no macros or preprocessor substitutions in Swift.
More Phun Phacts
- Swift is Completely Open-Source (Apache 2.0 License w/Runtime Exception)
Apple has published the complete source code for Swift. The link is at the end of this presentation.
- Works On All Apple Platforms, and is ABI-Stable
Swift works as the native development language for every supported Apple platform.
As of Swift 5.0, it is now ABI-stable, which means that its libraries are shipped as a part of the operating system.
- There Is An Official Apple Port for Linux
Apple officially supports Linux with Swift. The link is at the end of this presentation.
There is a third-party runtime environment for building and running Swift on Microsoft Windows. You can also cross-compile for Windows, using clang.
- You Can Have Swift On the Server (Vapor)
There is an open-source server implementation of Swift, using an open-source framework, called Vapor.
- Swift Is Apple’s Official Language for System and Native Development
If you want to write native software for any Apple product, you’ll need to do it in Swift. Objective-C isn’t going away any time soon, but don’t expect to see much support for it.
Additionally, with Swift 5.1, Apple has introduced a new runtime framework, called “SwiftUI.” This is not usable from Objective-C.
Why I Love Swift
- It Has Most of the Benefits of Scripting Languages, but Is Compiled
- Protocols, Extensions and Enums Are Amazing in Swift
- Nice Generics
- Optionals Are Extremely Useful
- Powerful Branches
- Powerful Collections and Ranges
I’m really excited about Swift, and am constantly learning more about how much care and planning was put into its design.
Compiled, but Looks Like A Scripted Language (Playground 0)
Swift looks a lot like most interpreted (or VMed) languages, but is a completely compiled and linked language.
Swift (and its Cocoa API) has all kinds of stuff to deal with memory leaks. It uses reference counting to manage allocation and deallocation of objects; which is far more efficient than garbage collection, and its reliance on value semantics helps to reduce the occurrence of “reference leaks.” Leaks are still possible, but you need to work to get them. Reference counting is something that a fully-resolved and compiled language can have.
Apple, when it it developed Swift, took the opportunity to add extra capabilities to many of its lower-level APIs (like Core Foundation), and put in things like memory leak protection. So, for example, you no longer need to call
Swift allows you to do a lot of runtime querying of instance and state. There’s nothing particularly new or innovative about this, but it’s not usually a feature found in compiled languages. You can also customize the way that Swift objects respond to introspection.
- Rich Standard Library That is Fully Integrated Into the Language
The Swift Standard Library is extremely rich. Many of the atomic Swift types are actually compositions of fundamental language characteristics, like protocols and extensions. With the Standard Library, Swift is incredibly powerful. The Standard Library takes advantage of Swift’s abilities to completely insinuate itself into the language, as does the Apple-specific Foundation Library.
- Playgrounds Are Really Nice, and Allow You to Pretend Swift is Interpreted
Playgrounds are new for Swift. They allow you to write and execute code in a “near-interpreted” fashion; with instant feedback and meta-information. They also work on iPads.
- Command-Line/Shell Support
Swift is built into the macOS/iOS/tvOS/watchOS operating system, and is available as a command-line scripting-style language.
- Very Safe, With Strong Compile-Time Checking
Safety is the #1 reason that Swift was developed. It has a great many characteristics that make it secure, robust and tight. Because it’s a compiled language, everything is resolved by the time the program starts running.
REFERENCE: How Mirror Works
Protocols (AKA “Interfaces”) (Playground 1)
- Swift Does Not Support Abstract Classes -Use Protocols, Instead
Swift implements interfaces (if you come from Java), as something called “Protocols.”
Protocols were introduced as a language extension to Objective-C, but have been made an integral part of Swift.
A protocol is a “contract” that infers that a data type will offer a particular set of functionality or properties. In Swift, we can also use protocols to [relatively] safely add “mixin” functionality.
Swift has no such thing as an “abstract” class. Instead, we use protocols, which can be applied to more than just classes.
Swift has elevated almost every data type into the realm of “first class citizen.” Classes are now only a single choice, amongst many different types. Protocols can be applied to almost all of them.
- Similar to Java Interfaces
If you are familiar with Java Interfaces, Swift Protocols will be familiar.
- Can Have Default Methods/Calculated Properties (Like Java 8+ Interfaces)
Like Java 8 (and up) Interfaces, you can add default functionality to Protocols. Unlike Java Interfaces, however, there’s no “inheritance.” Conflicting default implementations simply cancel each other out. You can’t choose to access one or the other of the inherited methods/properties, like you can in Java (or C++ multiple inheritance).
- Can Be Applied to Structs, Classes and Enums
Protocols aren’t just for classes. They can be applied to structs and enums, as well.
- Can Inherit From Other Protocols
Protocols can be inherited. Default implementations must remain unique throughout the chain, however, to remain viable.
- Can Be Specialized, to Apply Only Under Certain Conditions
You’ll be seeing this a lot. Swift has a “where” clause, which allows you to restrict all kinds of things to certain conditions. Protocols can be written so they only apply if the implementation meets certain requirements. This has the advantage of allowing the Protocol to make assumptions that would not be possible under more generic circumstances.
REFERENCE: Swift protocols
Extensions (Playground 2)
- Allow Addition of Functionality to Protocols, Classes, Structs, Enums and Types
Extensions are becoming fairly common these days. They are a safe way to add functionality to opaque data types. In Objective-C, these are known as “categories.”
In the case of Swift, you can extend virtually any of the atomic data types, as well as most of the Foundation types.
- Do Not Allow Stored Data/Properties to be Added
You can’t do that in Swift. You can add what are called “calculated properties,” but not “stored properties” to data types.
“Calculated properties” are a fairly neat construct, where you write a function that masquerades as a stored property.
For example, you can add a “property” to the Foundation String type that delivers an MD5 hash of that String.
- Must Resolve at Compile Time
All properties, functions, methods and instances need to be fixed at compile/link time, so extensions are static constructs; not runtime.
- Can Apply Throughout the Module Namespace
Extensions can apply throughout the module’s namespace, so if you add an extension to the String type in one source file, it will be available in other source files within that module. They can also be exported from a module’s namespace.
- Can Be Inherited Through Protocols or Subclassing
Extensions can be inherited via protocols (which can be extended) or through class inheritance. One thing about protocol extensions (default implementation), is that they are “1-layer deep.” They cannot be overridden, and conflict with other protocols or classes will result in the protocol default implementation being ignored.
- Can Be Specialized, to Apply Only Under Certain Conditions
As with other Swift constructs, a where clause can be applied to extensions, so they only apply under certain conditions. For example, you could make an Array extension return a DateComponents, but only in cases where the Dictionaries Element type is String. Dictionaries of Int would not be able to return the DateComponents in the same way (you could define another extension that returns a
DateComponents if the Int Array has the various components in it, though), so both extensions would have the same function signature, but two different code paths).
REFERENCE: Swift Extensions
Enums (Playground 3)
Swift takes enumerations to a whole new level.
- Behave More Like Classes Than Macros
In Swift, enums are “smart.” They behave a lot more like classes than simple macros.
The biggest difference between Objective-C and Swift, is that all enums in Objective-C shared the global namespace, so you had to jump through hoops to define them, like “NSAnimationEffectDisappearingItemDefault”.
In Swift, each enum has its own namespace, so if you declare your constant or variable as “NSAnimationEffect”, then you only need to specify “.disappearingItemDefault” as the particular subtype.
- Can Have Associated Data Values (Applied When Instantiated)
You can associate data with enums, which makes them ideal for tasks like defining errors. For example, the enum case could hold the general error category, and the associated data might be specific error information.
- Can Be Based on Types
You can associate an enum with a particular type, such as strings, so that each case has a static value. It can get a LOT fancier than that, but we’ll skip the jazz improv for now.
- Can Be Extended
You can extend enums, like you can other classes and structs in Swift. You can’t add new cases, but you can add new functionality.
- Enums Can Conform to Protocols, or Use Generics
Enums can conform to certain protocols, and can use generics. It can get tricky. Probably a good idea not to get too creative.
- Can Be Specialized, to Apply Only Under Certain Conditions
As with other types, you can specialize enums and enum extensions.
REFERENCE: Swift Enumerations
Generics (Playground 4)
Swift has a very “friendly” implementation of generics.
- Declaration Similar to C++ Templates or Java Generics
The generics declarations are greater-than/less-than symbol-delimited (<..>) declarations that apply to…
- Apply to Types, Protocols, Functions, Enums, Structs and Classes
…protocols, types, classes, structs and enums.
- Relatively (Deceptively) Simple
It’s deceptively simple (like many things in Swift).
- Language Will “Hide” Generics When They Can be Implied (Type Inference)
One of the really nice features of Swift’s generics, is that they don’t need to be obvious, if there’s no need to know about what’s under the hood. For example, Arrays are generic, but you never see the generic declaration notation for Arrays (unless you really want it). This is called “Type Inference,” and means that the compiler will use whatever information is available at the time the generic is specialized to determine its parameters. It usually gets it right first time, and you won’t need to do anything more.
- Can Be Propagated to Extensions
Generics can “propagate” into extensions of generic types.
- Can Be Specialized, to Apply Only Under Certain Conditions
Like most things in Swift, generics can have constraints added, that restrict their application, scope, namespace and relevance.
REFERENCE: Swift Generics
Optionals (Playground 5)
Swift doesn’t have pointers.
In C, pointers are a way to have direct memory access, and also to have a way to define an “invalid” state (an empty pointer). They also allow data to be referenced; avoiding copying.
As computing has progressed, the idea of where, exactly, some data or execution thread is, has become elastic (for example, the item could be in a register, in a GPU, in a cache, in memory, on disk, or even in another device), and pointers have not been able to adjust.
Pointers are also a fairly dangerous tool. Although powerful, they allow for serious bugs.
C++ has changed to a system of “smart pointers,” which are safer, and can flex a bit.
Most scripting and server development languages don’t have pointers at all.
Swift does allow some direct memory access, but it takes conscious work. It is usually only done when interacting with C.
Nevertheless, the concept of a “nil pointer” is important. In dynamic environments, it’s entirely possible to have data unavailable, or have execution paths change.
- Allow A Type-Safe Way to Specify nil
Optionals can be nil, and that gives us that one aspect of pointers that is still highly relevant to most developers, these days.
- Can Be Written to Be Ignored If nil, or Crash If nil
With optionals, you can use implicit optionals, which will crash if they are nil (which is not always a bad thing. Sometimes a crash is better than something like a security breach).
- Can Be “Chained” -A nil Anywhere In A Long Statement Can Fail the Statement
Or you can “chain” optionals, so that a statement or assignment can execute a number of cascading steps. If any one of them is nil, then you can safely catch that, and decide to switch the execution thread or exit the procedure.
- No Pointers Necessary
Between optionals and the reference-counted memory access model that Swift uses, pointers aren’t necessary. Swift will maintain internal references for as long as possible; avoiding memory allocation duplication (another main reason for using pointers). Swift also has a rich sequence functionality, so it’s possible to iterate or step through collections in many ways.
- Are “Resolved” by “Unwrapping”
In order to use the instance or memory referenced by an optional, you “unwrap” the optional. You can do this explicitly (using a question mark), or implicitly (the optional is defined using an exclamation mark, but you don’t do anything special when using the optional). There are a couple of other ways to deal with optionals, which will be mentioned in the playground accompanying this slide.
- Are Defined With Types/Classes/Structs, etc., But Apply to Instances
Optionals are runtime tools, but, like all things Swift, need to be defined when writing the code. You check (or don’t check) an optional at runtime, but it still needs to be fully resolved at compile time. Any data structure in Swift can be referenced using an optional, but it’s important to note that optionals aren’t the same as reference semantics. They are simply a way to have a nil value at runtime. In some cases (like weak references), optionals are required, but they are simply one of a set of tools.
REFERENCE: Swift Optionals
Branches (Playground 6)
Swift has a great array of choices for making choices.
- Can be Used to Create Conditional Context, Including Instances
One of the nice things about some of the branches, is that you can use them to establish context, and/or unwrap optionals.
You can use some branches to establish a conditional context; dependent upon successful satisfaction of the condition. This can actually be “chained.” Very cool.
- Can be Used to Safely “Short-Circuit” Execution, Like Exceptions, But Better
You can keep execution from completing, like you can with exceptions, except these are much safer ways to do it (exceptions are problematic).
- No Real Exceptions -Throws Are More Like Breaks, not Stack-Unwrappers
Swift doesn’t have the types of exceptions that C++ has. That’s a good thing. Exceptions are extremely problematic; especially in threaded and asynchronous environments. They can also clobber performance.
What Swift has, is “throws”. These are defined like exceptions, but without all the stack-smashing chaos of real exceptions. You are forced to deal with them properly (and simply).
Throws are designed explicitly as error handlers. You can combine them with enums for a really powerful error handling capability.
- Switches Are Awesome
Switch statements are VERY powerful in Swift. You can use strings and conditions, like you can with interpreted languages, or even ranges.
- Very Safe Branches
Branches in Swift are very safe. The compiler always makes sure they are exhaustive. No “loose ends.”
- Can Be Integrated Into Loops
You can integrate tests into for loops, so the loop is filtered.
REFERENCE: Swift Branch Statements
Collections and Ranges (Playground 7)
- Swift Has Many Powerful Standard Collections
The Swift Standard Library (Foundation) comes with a number of built-in collection types, and –quite literally– dozens of protocols that can be used to “roll your own.”
- Arrays, Sets, and Dictionaries
- Great Support for Collection Folding and Visiting (Higher Order Functions)
The built-in collection types support functional programming-style higher order functions for folding and visiting, like map/compactMap, reduce, and forEach.
- Many Standard Protocols and Extensions Apply to Collections
The Swift Standard Library comes with dozens of protocols that can be used to turn almost any type, class, struct or enum into a collection, with support for higher-order methods, generics, iterations and various combinatorial operations.
- Ranges and Strides Can Be Used for Iteration and Matching
Ranges and Strides are an enormous topic, all to themselves. The companion playground to this slide will be the biggest one of the lot, and explores them in detail.
The most obvious use for Ranges and Strides, is for iterating loops. Strides can help you to iterate backwards, or in non-integer steps.
- Ranges Can Be Used As Select Cases
Suffice to say that you can do A LOT with Ranges. You can use them as select cases. For example, you can have a select case from 0 to 9, and if the switch value is 7, it will fall into that.
You can also use Ranges and Strides as collection generators.
REFERENCE: Swift Collection Types
I hope that you enjoyed this brief introduction, and that it whets your appetite to learn more about Swift. This was just the tiniest little taste. There’s a LOT more out there.
The Swift community is growing rapidly, and people are really excited about the language.
- If You Want to Write Apple Software; Learn Swift.
Swift is now the official language for all Apple native programming; including inside Apple. Objective-C will still be around for quite a while, but don’t expect it to get a whole lot of attention from Apple.
It isn’t your only choice for writing Apple software, but it is pretty much your only choice for writing true native Apple software.
- It Looks Like A Scripting Language, But Behaves Like A Compiled One.
Swift has many aspects that look like interpreted (or VMed) scripting languages, but it is a fully-compiled language that enjoys all of the advantages of a compiled and linked systems development language.
- It Has Incredibly Rich Data Types, Collections, and Branches.
It has incredibly rich data types, where “everything is a first-class smart object.” It has tuples, structs, classes, powerful enums, arrays, directories, sets, loops, recursion, etc. The whole enchilada.
Also, it’s not exactly “everything is an object,” as it prizes value semantics, so everything is “smart,” but doesn’t necessarily have to be an object.
- It Can Be Used for Object-Oriented Programming.
Swift is an excellent language to use for traditional Object-Oriented Programming. It supports classes, polymorphism, encapsulation and [single] inheritance.
- It Can Be Used for Protocol-Oriented Programming.
Swift’s powerful protocol/interface system, and its rich standard library, afford what is called “Protocol-Oriented Programming,” which can give you a “safe” mixin programming style.
- It Can Be Used for Functional Programming.
Swift is not a “pure” Functional Programming language, like Haskell, but it has implemented pretty much all the structures and behaviors necessary for FP, and you should be able to use it as an FP language.
- It is Very Safe.
Swift was designed from Day One to be a very safe language. It has great guardrails, without restricting you. It’s really difficult to leak memory, overrun buffers or access protected data; yet it never seems to have visible restrictions. It lets you do pretty much whatever you want to do.
Many Rabbit-Holes to Explore
- Cross-Compiling Swift for Windows, Using clang
- How Mirror Works
- Swift Protocols
- Swift Extensions
- Swift Enumerations
- Swift Generics
- Swift Optionals
- Swift Branch Statements
- Swift Collection Types