Slide 1

Slide 1 text

I m p r o v i n g y o u r Developer Experienc e with Open-Source Swift Dimitri Dupuis-Latour @dupuislatour 2018

Slide 2

Slide 2 text

Story

Slide 3

Slide 3 text

Xcode in Xcode Xcode.xcodeproj

Slide 4

Slide 4 text

Xcode in Xcode

Slide 5

Slide 5 text

Xcode in Xcode 1

Slide 6

Slide 6 text

Swift

Slide 7

Slide 7 text

Open-Source Swift

Slide 8

Slide 8 text

Open-Source Swift

Slide 9

Slide 9 text

Open-Source Swift

Slide 10

Slide 10 text

How ?

Slide 11

Slide 11 text

Toolchain

Slide 12

Slide 12 text

Toolchain

Slide 13

Slide 13 text

Toolchain

Slide 14

Slide 14 text

How ?

Slide 15

Slide 15 text

https://github.com/apple/swift README git clone 1 repository ./swift/utils/update-checkout 14 repositories 2GB source code ./swift/utils/build-script ≈1 hour (full build in debug) ≈70 GB of build artifacts

Slide 16

Slide 16 text

Swift checkout

Slide 17

Slide 17 text

Swift checkout

Slide 18

Slide 18 text

Swift checkout

Slide 19

Slide 19 text

Swift checkout

Slide 20

Slide 20 text

Compiler 
 aka ‘lib’

Slide 21

Slide 21 text

Compiler 
 aka ‘lib’ AST SourceKit Fixits Warnings Refactoring Engine

Slide 22

Slide 22 text

Compiler 
 aka ‘lib’ AST SourceKit Fixits Warnings Refactoring Engine

Slide 23

Slide 23 text

Refactoring Engine

Slide 24

Slide 24 text

Refactoring Engine Xcode SourceKit

Slide 25

Slide 25 text

Adding a new Refactoring « Frenchify »

Slide 26

Slide 26 text

Refactoring Engine RefactoringKinds.def : CURSOR_REFACTORING(Frenchify, "Frenchify", frenchify.expr)

Slide 27

Slide 27 text

Refactoring Engine RefactoringKinds.def : CURSOR_REFACTORING(Frenchify, "Frenchify", frenchify.expr) Refactoring.cpp : bool RefactoringActionFrenchify::isApplicable(ResolvedCursorInfo CursorInfo) { return true; }

Slide 28

Slide 28 text

Refactoring Engine RefactoringKinds.def : CURSOR_REFACTORING(Frenchify, "Frenchify", frenchify.expr) Refactoring.cpp : bool RefactoringActionFrenchify::isApplicable(ResolvedCursorInfo CursorInfo) { return true; } bool RefactoringActionFrenchify::performChange() { return false; // Return true if code change aborted. }

Slide 29

Slide 29 text

Refactoring Engine RefactoringKinds.def : CURSOR_REFACTORING(Frenchify, "Frenchify", frenchify.expr) Refactoring.cpp : bool RefactoringActionFrenchify::isApplicable(ResolvedCursorInfo CursorInfo) { return true; } bool RefactoringActionFrenchify::performChange() { EditConsumer.insert(SM, Cursor.TrailingExpr->getStartLoc(), "Le "); return false; // Return true if code change aborted. }

Slide 30

Slide 30 text

Refactoring Engine RefactoringKinds.def : CURSOR_REFACTORING(Frenchify, "Frenchify", frenchify.expr) Refactoring.cpp : bool RefactoringActionFrenchify::isApplicable(ResolvedCursorInfo CursorInfo) { return true; } bool RefactoringActionFrenchify::performChange() { EditConsumer.insert(SM, Cursor.TrailingExpr->getStartLoc(), "Le "); EditConsumer.insertAfter(SM, Cursor.TrailingExpr->getEndLoc(), " "); return false; // Return true if code change aborted. }

Slide 31

Slide 31 text

Xcode

Slide 32

Slide 32 text

Le Xcode

Slide 33

Slide 33 text

https://swift.org/blog/swift-local-refactoring More Examples

Slide 34

Slide 34 text

"But I am not a compiler engineer !" — Joe, average iOS developper

Slide 35

Slide 35 text

https://github.com/apple/swift

Slide 36

Slide 36 text

Standard Library 
 aka ‘stdlib’

Slide 37

Slide 37 text

Bool.toggle() Swift 4.2, Chris Eidhof extension Bool { @_inlineable /// Toggles the value of the Boolean. /// /// Calling this method sets the variable to `true` if it was `false`, /// and sets it to `false` if it was `true`. For example: /// /// var bools = [true, false] /// /// bools[0].toggle() /// // bools now contains [false, false] public mutating func toggle() { self = !self } } [SE-0199] Adding toggle to Bool

Slide 38

Slide 38 text

Dictionary.compactMapValues() Swift 5 /// Returns a new dictionary containing the keys of this dictionary with the /// values transformed by the given closure. /// - Parameter transform: A closure that transforms a value. `transform` /// accepts each value of the dictionary as its parameter and returns a /// transformed value of the same or of a different type. /// - Returns: A dictionary containing the keys and transformed values of /// this dictionary. @inlinable // FIXME(sil-serialize-all) public func compactMapValues( _ transform: (Value) throws -> T? ) rethrows -> Dictionary { return try self.reduce(into: [Key: T](), { (result, x) in if let value = try transform(x.value) { result[x.key] = value } }) } [SE-0218] Introduce compactMapValues to Dictionary

Slide 39

Slide 39 text

Sequence.countWhere() Swift 5 [SE-0220] count(where:) extension Sequence { /// Returns the number of elements in the sequence that satisfy the given /// predicate. /// /// […] /// - Parameter predicate: A closure that takes each element of the sequence /// as its argument and returns a Boolean value indicating whether /// the element should be included in the count. /// - Returns: The number of elements in the sequence that satisfy the given /// predicate. @inlinable public func count( where predicate: (Element) throws -> Bool ) rethrows -> Int { var count = 0 for e in self { if try predicate(e) { count += 1 } } return count } }

Slide 40

Slide 40 text

Let’s talk !