Top Banner
Swift 5, ABI Stability and Concurrency @phillfarrugia
40

Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Dec 02, 2018

Download

Documents

buixuyen
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Swift 5, ABI Stability and Concurrency@phillfarrugia

Page 2: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Important Documents• Concurrency Manifesto by Chris Lattner

https://gist.github.com/lattner/31ed37682ef1576b16bca1432ea9f782

• Kicking off Concurrency Discussions by Ted Kremeneckhttps://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170814/038891.html

• Async/Await Proposal for Swift by Lattnerhttps://gist.github.com/lattner/429b9070918248274f25b714dcfc7619

Page 3: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

• Prototype for Async/Await by Lattnerhttps://github.com/apple/swift/pull/11501

• Swift Evolution Goals for Swift 5https://github.com/apple/swift-evolution/blob/master/README.md

• Swift ABI Stability Manifestohttps://github.com/apple/swift/blob/master/docs/ABIStabilityManifesto.md#what-is-abi-stability

• Swift Unwrapped Podcasthttps://spec.fm/podcasts/swift-unwrapped/84323

Page 4: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Goals for Swift 5

Page 5: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Primary Focus: ABI StabilityWhat is ABI Stability?At runtime Swift binaries interact with other libraries and components through an ABI (Application Binary Interfaces). It defines low level details like how to call a function, how data is represented in memory and where metadata is and how to access it.

Currently Swift is not ABI stable, so each binary (App), bundles its own version of the Swift Dynamic Library. Swift doesn’t live on the iOS Operating System, it lives within each App.

Page 6: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

That means Sephora Color IQ is using Swift 3.1, so it bundles Swift 3.1’s Dynamic Library (containing the 3.1 ABI) inside. But the Gap app is using Swift 2.3, so it bundles Swift 2.3 and it’s 2.3 ABI.

If Swift becomes ABI Stable, Swift will live within the iOS Operating System and it’s ABI will be compatible with every version of Swift. i.e Sephora Color iQ is using Swift 5.0, but Gap is using Swift 4.3, and their both consuming Swift ABI embedded in the Operating System.

Page 7: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Why does ABI Stability matter?

• Bundle size is reduced• Language changes smaller / Less frequent• Less Migration• Developers can create Pre-compiled Frameworks in Swift (currently

frameworks are compiled when compiling your app) because no need to embed Swift

Page 8: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Drawbacks?

• Limits changes to the Public Interfaces and Symbols• Restricts the ways Swift can grow and evolve

Page 9: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

String Ergonomics• Aim to complete more work outlined in the String Manifesto• Language level support for Regular Expressions?• Performance Improvements to the internal implementation of

String

Page 10: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Standard Library Improvements• Only making minor changes to improve Standard Library where

needed

Page 11: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Foundation Improvements• Improvements Foundation that make using the Cocoa SDK with

Swift more seamless

Page 12: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Syntactic Additions• Syntactic changes add complexity to the language• May be made but only if well motivated, under intense scrutiny

Page 13: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Groundwork/Discussion for new Concurrency Model• Finalizing the model is a non-goal for Swift 5• Key focus area is designing language affordances for creating and

using asynchronous APIs and problems caused by callback-heavy code

Page 14: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Changes to the Swift Evolution Process for Swift 5• Unlike Swift 4, there will not be Stage 1, Stage 2…etc for accepting

proposals• Proposals are welcome until March 1, 2018• To mitigate the risks of proposals distracting from ABI Stability,

EVERY evolution proposal will need a working implementation with test cases before it can be considered for review.

Page 15: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

How to Submit a ProposalStep 1 Write Proposal, submit via Pull Request to swift-evolution repository

Step 2Core Team provides feedback

Step 3If positive feedback, author must provide an implementation prior to proposal being formally reviewed.

Page 16: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Concurrency Manifestoby Chris Lattner

Page 17: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Introduction• Focuses on Task-Based Concurrency Abstractions (common in

Event-Driven, Client-Server Applications i.e responding to UI events or requests)

• Swift 1…4 has avoided Concurrency, relied on OS/Library level abstractions (GCD, pthreads, NSThread, etc) to manage tasks.

• It’s already possible to use GCD..etc, so the Goal is to make the Concurrency experience far better than it is today

• Improve the concurrency story with Swift’s values - Design, Maintenance, Safety, Scalability, Performance and Excellence

Page 18: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Why a First Class Concurrency Model?

Page 19: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Asynchronous APIs are difficult to work• Error Handling, Callbacks, when performing multiple operations

creates complicated control flows• Made worse with Swift’s guard let syntax throughout callback

closures

Page 20: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Hard to know what Queue/Thread you’re on• Swift closures don’t make it obvious which background thread or

queue a task is being executed on• Leads to race conditions, and unexpected results

Page 21: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Shared mutable state Is bad for Software Developers• Data being mutated while someone else is reading from it• Typically solved using mutexes or locks, but this introduces a

number of problems: ensuring you’re using the right locks, granularity of locks, avoid deadlocks and other issues.

• Mutexes are inefficient• Techniques like Objective C read/copy/update are complex, unsafe

and fragile

Page 22: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

4 Major Abstractions in Computation• Traditional Control Flow• Asynchronous Control Flow• Message Passing and Data Isolation• Distributed Data and Compute

(1) Already exists in Swift(2) Asynchrony is the next step towards Concurrency model. Fundamental to machines talking to other machines, slow devices and multiple operations.(3) Next step is to define a programmer abstraction to define and

Page 23: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Current Asynchronous Solution in Swift• Passing “Completion handlers” using closures• Completion handlers stack up to a pyramid of doom• Make error handling awkward• Make control flow extremely difficult

Page 24: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Part 1 - Async/Await Pattern

Page 25: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Async• Well known solution used in other popular programming languages

- C, C#, Python, Javascript, Scala with great success.• Async keyword used similar to the existing throws keyword• Declare a function as async to indicate function is a Coroutine.

Definition: Coroutines• Functions that may return a value normally, or may suspend

themselves and internally return a continuation.

Page 26: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Await• Similar to the existing try keyword.• Indicates that non-local control flow can happen at that point.

Page 27: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Before:func loadWebResource(_ path: String, completionBlock: (result: Resource) -> Void) { ... }func decodeImage(_ r1: Resource, _ r2: Resource, completionBlock: (result: Image) -> Void)func dewarpAndCleanupImage(_ i : Image, completionBlock: (result: Image) -> Void)

func processImageData1(completionBlock: (result: Image) -> Void) { loadWebResource("dataprofile.txt") { dataResource in loadWebResource("imagedata.dat") { imageResource in decodeImage(dataResource, imageResource) { imageTmp in dewarpAndCleanupImage(imageTmp) { imageResult in completionBlock(imageResult) } } } }}

Page 28: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

After:func loadWebResource(_ path: String) async -> Resourcefunc decodeImage(_ r1: Resource, _ r2: Resource) async -> Imagefunc dewarpAndCleanupImage(_ i : Image) async -> Image

func processImageData1() async -> Image { let dataResource = await loadWebResource("dataprofile.txt") let imageResource = await loadWebResource("imagedata.dat") let imageTmp = await decodeImage(dataResource, imageResource) let imageResult = await dewarpAndCleanupImage(imageTmp) return imageResult}

Page 29: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Part 2 - Actors

Page 30: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

What is an Actor?• Actors represent real world concepts like “a document”, “a device”, “a

network request”• Well suited to event driven architectures like UI applications and

servers • An actor is a combination of a DispatchQueue, the data that queue

protects and messages that can be run on the queue• An Actor would be a new ‘type’ in Swift, like class, struct or protocol

Page 31: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

• Allows programmer to define internal variables and functions to manage that data and perform operations on it

• Actors can’t return values, throw errors or have inout parameters

Page 32: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Main Thread?• UIKit and AppKit would model something like the ‘Main Thread’

using a ‘MainActor’• Programmers could define extensions to the MainActor in order to

run their code on the main thread.• Actors are shutdown when their reference count reaches 0 and the

last queued message is completed.

Page 33: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

actor TableModel { let mainActor : TheMainActor var theList : [String] = [] { didSet { mainActor.updateTableView(theList) } }

init(mainActor: TheMainActor) { self.mainActor = mainActor }

// this checks to see if all the entries in the list are capitalized: // if so, it capitalize the string before returning it to encourage // capitalization consistency in the list. func prettify(_ x : String) -> String { // Details omitted: it inspects theList, adjusting the // string before returning it if necessary. }

actor func add(entry: String) { theList.append(prettify(entry)) } }

Page 34: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Part 3 - Fault Isolation

Page 35: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

• Far more complex and low level than Part 1 and Part 2• Most important thing to note is that by using the Actor model, state

is no longer global• Therefore if a crash was to occur in a particular Actor, it could be

possible to terminate just the Actor that had an issue instead of the whole process

• This also has possible downsides such as if some other Actor or piece of code is awaiting that Actor to finish a task but it has terminated and will never return

Page 36: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Part 4 - System Architecture

Page 37: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

• Wayyyy more complex than everything else• Interprocess Communication and managing basic async operations

is similar in many ways• Independent tasks communicating with each using by sending

structured data using asynchronous messages• But there’s also a lot of things not similar• A Swift Developer shouldn’t have to worry about IPC if they don’t

care about it• Actors can opt in to distribution using the distributed keyword• Requires that actors conform to a few different requirements in

order to allow them to work with distributed systems.

Page 38: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

Part 5 - The crazy and brilliant future

Page 39: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

• Room to extend upon Actors and asynchrony to improve long-standing Software Community divides (that are all way to complicated for me to mention here)

Page 40: Swift 5, ABI Stability and Concurrency · actor TableModel {let mainActor : TheMainActor var theList : [String] = [] {didSet {mainActor.updateTableView(theList)}} init(mainActor:

FIN