Swift 3 and Declarative Programming

The times, they are a-changin’, as Swift 3 brings with it over forty community-driven changes. The overarching mission is continued modernization and refinement of the language with many sweeping, syntax-breaking changes in preparation for stable ABI, after which such changes would be far more difficult to implement. A comprehensive list of changes accepted for the first developer preview can be found on the Swift blog, and you can track and even engage with the process in real time via the Swift Evolution repository.

The most dramatic source-breaking change in Swift 3 is a vastly improved method of importing of Objective-C API. Alongside API overhaul, Swift API Design Guidelines have been significantly updated, and I highly recommend you read the entire document. To me, these changes mean much more than, “Yay, interfacing with Foundation and UIKit is getting even more Swifty!” It represents a major step forward in Swift’s embracing of some of the guiding principles that can be found in declarative and intentional programming.

Declarative Programming

Declarative Programming is a paradigm in which programs are composed of descriptions of operations, conditions, and problems, rather than specific implementations of algorithms — which falls under the Imperative Programming paradigm. Put more simply, declarative programs state what to do, and imperative programs state how to do it. If you were tasked with fetching entries from a table matching a specific condition, then sorting them on a specific criteria, a declarative program might look something like this:

data -> fetch { condition } -> sort { criteria }

Notice how Swifty this example looks! An equivalent imperative implementation might be hundreds of lines long with very specific implementation details.

At this point it is worth mentioning Intentional Programming, a concept or paradigm credited to Charles Simonyi, who was an employee at Microsoft at the time that he developed it. If object-oriented programming means writing code that represents objects, then intentional programming is writing code that represents the intentions of the programmer. To best achieve this, statements should read like prose, and use as few esoteric symbols, grammers, and formats as possible. Another ideal of intentional programming is that programmers should be able to express their intentions in any language — no, not C++, Ruby, or Swift; think English, German, or Japanese. While I don’t think Swift’s core language syntax will allow you to write

für

instead of

for

any time soon, having full Unicode support does allow programmers to use diacritics, non-Roman alphabets, or even emoji to name their types, functions, and variables in their native tongue.

Intentional and declarative programming share a common goal of favoring brevity and expressiveness. One way to achieve these goals is to prune away aspects of code that solely exist to help the machines process or execute it, leaving behind clearer, cleaner code that more closely represents the purpose of its existence in the first place. Swift has a number of language features that are conducive to this paradigm, including type-inference, which greatly reduces the amount of characters in lines of code that are not germain to purpose of the code, especially when compared to Objective-C.

Learning to Count

When learning a language, either spoken or programmatic, learning counting from one to ten is often one of the very first steps. Let’s use this classic example to demonstrate what intentional programming could look like, and compare it to an imperative and declarative example. Ideal intentional pseudocode for printing one to ten might look something like this:

print each number from 1 to 10

Notice how closely this program resembles the description of task it was written to fulfill! Standing in stark contrast, the following imperative implementation of this program in C explicitly describes every step of the algorithm:

int main () {
int a;
for(a = 1; a <= 10; a++) {
printf("%d\n", a);
}
return 0;
}

When comparing these two examples, notice how many extra lines, symbols, and distractions are added. Finally, let’s take a look at a sample declarative Swift implementation:

(1...10).forEach { print($0) }

We’ve come pretty close our original pseudocode goal! Reading from right to left, we have nearly all of the same elements: “print”, “each”, and “1 through 10”. Since a single line of code is considered a valid Swift program, we can do away with things like

int main()

and

return 0;

. Finally, while not entirely clean, we’ve significantly reduced the number of esoteric symbols, such as

%d\n

,

++

,

<=

, and

;

, lending to a much more readable statement.

Cutting the Cruft

At their hearts, the core goal of both declarative and intentional programming is clarity of intent — declaring

sort(data)

clearly communicates the operation being executed, and what it is being executed on, whereas a full sorting algorithm implementation provides ample opportunity for distraction from the statement’s ultimate purpose. The Swift 3 Cocoa Touch APIs have been transformed based on a new set of API guidelines and importing rules to be much more Swifty; breaking away from the Objective-C-rooted convention of liberally decorating interfaces with type information. This change was not motivated by conciseness for its own sake, but by a desire to have clarity of intent at the call site, and the result is very clear, prose-like syntax.

In Swift 2.2, one might have dismissed a view controller with the following statement:

dismissViewControllerAnimated(true, completion: nil)

In Swift 3, we would write:

dismiss(animated: true, completion: nil)

In this version, we cut

ViewController

out of the signature entirely, since it should be obvious what we are dismissing, and move animated to a parameter label, paring down the base function signature to a simple dismiss. The consistent handling of parameter labels reads far more cleanly, and places emphasis on the core purpose of the function.

Let’s examine another example in Foundation. If we wanted to trim leading and trailing whitespace from a string, we might write:

"   hello world   ".stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet()) // “hello world”

The Swift 3 version of this call is about 30% shorter reads much more like natural language.

"   hello world   ".trimmingCharacters(in: .whitespacesAndNewlines) // “hello world”

Breaking away from old Objective-C sensibilities and taking advantage of Swift’s robust type inference engine allows us to write far more readable and intuitive code, and brings us one step closer to clarity that intentional and declarative programming call for. Swift API Guidelines go a step further in pushing for prose-like code by emphasizing grammars role in designing API.

Grammar Matters

The Swift API Design Guidelines state that one should “prefer method and function names that make use sites form grammatical English phrases.” Proposal SE-0006 takes this principle and applies it across the entire standard library.

Let’s investigate one way grammer plays a strong role in Swift API design. Often methods that modify a struct come in two flavors, a mutating version that alters the “source” struct, and a nonmutating version returns a new struct containing the alteration, leaving the “source” intact. Differentiating these two forms in API can be tricky. In Swift 2.2, one standard is to append InPlace to functions that mutate the source. This choice seems logical, but can be counterintuitive, as one may expect a method called sort to, well, sort the caller, as opposed to creating a new sorted structure. Swift 3 revises its API standards to behave in just that manner. Let’s look at an example.

/// Swift 2.2: ///
myArray.sort() // creates a new sorted version of myArray
myArray.sortInPlace() // sorts myArray

/// Swift 3: ///
myArray.sorted() // creates a new sorted version of myArray
myArray.sort() // sorts myArray

This is a far more elegant treatment, as the functional difference between the two methods is rooted in English grammar: “sorted” is a noun, and creates a new (sorted) thing, “sort” is a verb and performs an action on a thing. It is important to note an obvious consequence of this change: between Swift 2.2 and 3, the method sort changes from the nonmutating to mutating version, so be sure to look out for that as you adjust to Swift 3!

Designing APIs that are informed by native grammar makes code much more intuitive and prose-like, and aligns well with the declarative goal of writing programs that precisely state what they do. Beyond changes to API, Swift 3 brings with it many more changes that modernize and refine the language.

Other Animals

There are so many awesome changes in Swift 3, and this just covers a small fraction of only the first developer preview. I’d like to highlight a few of the changes I’m most excited for here, but be sure to read through the entire list for Swift 3.0 Preview 1, and keep your eye on the blog for future updates!

Adieu ++

In Swift 3, the language will be aggressively pruned of vestigial patterns rooted in or influenced by legacy languages and outdated paradigms, such as ++ / — and C-style for loops. As we saw with the example above, C-style for loops add a lot of cryptic syntax, and Swift provides us with a number of features for accomplishing the same tasks in a much cleaner fashion, such as

map

,

forEach

, and

for-in

loops. Removing the

++

and

--

operators is also a welcome change, as they are less useful in the absence of C-style for loops, and using them for basic incrementing and decrementing is easily accomplished with the more straightforward

+=

and

-=

operators.

Makeovers!

Two of Apple’s C-based APIs will be receiving shiny, new, Swifty makeovers! CGGraphics is a challenging API to work with, requiring the use of many globally-scoped functions, and pass-by-reference semantics. With Swift 3, instead of using functions such as CGContextSetLineWidth(…) or CGPathMoveToPoint(…), which require you to pass the context or path as an argument, we will be able to use object-oriented semantics like

context.lineWidth = 1.0

or

path.move(...)

.

GCD will be receiving a similar rework, with object types being converted to more conventional CamelCased Swift equivalents, and globally-scoped functions being moved to instance methods on these types. For example, to run an asynchronous block in Swift 2.2, we would need to use global methods to create a queue and dispatch to it:

let queue = dispatch_queue_create("com.helloworld.queue", nil)
dispatch_async(queue) {
print("hello world")
}

In Swift 3, we create a queue with an initializer, and dispatch to it with an instance method:

let queue = DispatchQueue.global().async {
print("hello world")
}

This rework feels distinctly clean and native, and is a welcome update to GCD.

Constant Overhaul

Objective-C Constant groups are also getting an overhaul. While enums and option sets declared with

NS_ENUM

/

NS_OPTIONS

in Objective-C were gracefully imported as native

enum: Int

types in Swift, there are many groups of

NSString

-based constants that were excluded from this translation, such as

HKQuantityTypeIdentifier

constants. In Swift 3, instead of importing them as raw global constants, they will be translated into an appropriate type, such as

enum: String

, allowing us to write exhaustive switch statements and use type inference to infer the base enum type. For example, the Objective-C declaration:

HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyMassIndex;
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyFatPercentage;
HK_EXTERN NSString * const HKQuantityTypeIdentifierHeight;
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyMass;
HK_EXTERN NSString * const HKQuantityTypeIdentifierLeanBodyMass;

will be now translated into Swift as:

enum HKQuantityTypeIdentifier : String {
case BodyMassIndex
case BodyFatPercentage
case Height
case BodyMass
case LeanBodyMass
}

Double the Value

Continuing the Swift-nativization trend, many Foundation types will be receiving a Swift-wrapper treatment similar to

String

. These types will be interfaced with as value types instead of reference types, allowing us to fully leverage

var

/

let

semantics with them. For example,

NSData

and

NSMutableData

will be combined into the Swift struct

Data

. Methods such as

appendBytes

would be available to

Data

variables declared with

var

, but not

let

. Passing

Data

s around through functions and declarations will follow the on-demand copy-on-mutation pattern that other structs use. This is a very welcome change, as it is generally preferred to work with value types instead of reference types in Swift — the standard library has 109 structs and only 6 classes — and will lead to more intuitive behaviors when composing and copying other value types.

A Farewell to Eccentricity

In addition to legacy-rooted features, a few of the more obscure language features will also be axed, including curry syntax and tuple splats. As a lover of cute and eccentric language features, I’ll be sad to see them go for at least a week after the final Swift 3 release, but it’s all in the name of progress. While Swift is definitely getting more lean and mean with this update, we are getting some nifty new Swift standard library features like sequence and first(where:)!

Bon Courage

With all of these sweeping, source-breaking changes, migrating to Swift 3 is bound to be quite the ordeal, and I wish you all the best of luck. My own project’s migration touched nearly 500 files, created a 4,000+ line diff, and nearly as many build errors, but the shining light at the end of the tunnel is more than enough to get me through it. There’s so much to explore with this update, and I’m looking forward to a new age of iOS programming where outdated API, legacy paradigms, and vestigial patterns are eliminated from Swift. If you’d like to share your favorite changes in Swift 3, or any new changes you would have liked to see in the final update, be sure to drop a comment below!

This article is part of our Welcome to iOS 10 series.

The post Swift 3 and Declarative Programming appeared first on Possible Mobile.

Originally published on Possible Mobile

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.