Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[SwiftCraft '24] Back to the Future: Swift 6 Edition!

[SwiftCraft '24] Back to the Future: Swift 6 Edition!

The next major version of Swift is expected to bring several major changes to the language to make it safer and more developer-friendly.
While some of these features will greatly improve our experience as Swift developers, they will also introduce breaking changes and compatibility issues. That's why I put together this talk, where I will outline and explain all the upcoming and show you, with plenty of code examples, what you can start doing now to get ready for Swift 6.

Pol Piella Abadia

May 24, 2024
Tweet

More Decks by Pol Piella Abadia

Other Decks in Programming

Transcript

  1. A n n o u ncemen t H el m

    I s s hi p p i n g T o d a y ! Whe n A p p l e ap p rov e i t!
  2. S wi f t 6 H ow t o get

    r e a d y f o r
  3. 6.0.0 M a jo r v er sio n B

    r e a k i ng c h a nge s P a t c h v er sio n B ug f i x e s , et c . M i no r v er sio n N o n - br e a k i ng c o n sid er a bl e c h a nge s
  4. 6.0.0 P n B c M n N s M

    a jo r v er sio n B r e a k i ng c h a nge s
  5. S w if t 6 SE-0270 SE-0364 SE-0408 SE-0410 SE-0416

    SE-0418 SE-0421 SE-0412 SE-0411 SE-0286 SE-0274 SE-0220 SE-0301 SE-0405 SE-0409 SE-0420 SE-0422 SE-0384 SE-0383 SE-0401 SE-0337 SE-0354 SE-0352 SE-0414 SE-0426
  6. S w if t 6 SE-0270 SE-0364 SE-0408 SE-0410 SE-0416

    SE-0418 SE-0421 SE-0412 SE-0411 SE-0286 SE-0274 SE-0220 SE-0301 SE-0405 SE-0409 SE-0420 SE-0422 SE-0384 SE-0383 SE-0401 SE-0337 SE-0354 SE-0352 SE-0414 SE-0426
  7. h t t ps :// p o d c a

    s t s . a p p l e . c o m / u s / po d c a s t /43- now - i m - w o r r ie d - o ur - met r ics - a r en t - c o r r e c t - wi t h / i d 1654567329? i =1000653584114
  8. S w if t 6 SE-0270 SE-0364 SE-0408 SE-0410 SE-0416

    SE-0418 SE-0421 SE-0412 SE-0411 SE-0286 SE-0274 SE-0220 SE-0301 SE-0405 SE-0409 SE-0420 SE-0422 SE-0384 SE-0383 SE-0401 SE-0337 SE-0354 SE-0352 SE-0414 SE-0426
  9. S w if t 6 Wit ho u t t

    h e S wi ft 6 la n g ua ge mo d e S w if t 6 SE-0270 SE-0364 SE-0408 SE-0410 SE-0416 SE-0418 SE-0421 SE-0412 SE-0411 SE-0286 SE-0274 SE-0220 SE-0301 SE-0405 SE-0409 SE-0420 SE-0422 SE-0384 SE-0383 SE-0401 SE-0337 SE-0354 SE-0352 SE-0414 SE-0426
  10. S wi f t 6 H ow t o get

    r e a d y f o r t he L a n g u a ge mo d e
  11. #! /bin/sh # Install `swiftenv` brew install kylef/formulae/swiftenv echo 'if

    which swiftenv > /dev/null; then eval "$(swiftenv init -)"; fi' >> ~/.zshrc I n s t a l l o n m a c OS
  12. #! /bin/sh # Install `swiftenv` brew install kylef/formulae/swiftenv echo 'if

    which swiftenv > /dev/null; then eval "$(swiftenv init -)"; fi' >> ~/.zshrc # Install the latest Swift 6 development toolchain swiftenv install 6.0-DEVELOPMENT-SNAPSHOT-2024-04-30-a I n s t a l l o n m a c OS
  13. #! /bin/sh # Install `swiftenv` brew install kylef/formulae/swiftenv echo 'if

    which swiftenv > /dev/null; then eval "$(swiftenv init -)"; fi' >> ~/.zshrc # Install the latest Swift 6 development toolchain swiftenv install 6.0-DEVELOPMENT-SNAPSHOT-2024-04-30-a # CD into your Swift package directory cd your-swift-package # Set the Swift 6 toolchain as the default for this directory swiftenv local 6.0-DEVELOPMENT-SNAPSHOT-2024-04-30-a I n s t a l l o n m a c OS
  14. #! /bin/sh # Install swiftly curl -L https: // swift-server.github.io/swiftly/swiftly-install.sh

    | bash # Install the latest Swift 6 development toolchain swiftly install 6.0-DEVELOPMENT-SNAPSHOT-2024-04-30-a # Set the Swift 6 toolchain as the active toolchain swiftly use 6.0-DEVELOPMENT-SNAPSHOT-2024-04-30-a I n s t a l l o n l i n ux
  15. class NonIsolated { func callee() async {} } actor Isolated

    { let nonIsolated = NonIsolated() func callee() async { await nonIsolated.callee() } }
  16. / / swift-tools-version: 6.0 import PackageDescription let package = Package(

    name: "Swift6Examples", platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ .library( name: "Swift6Examples", targets: ["Swift6Examples"] ) ], targets: [ .target(name: "Swift6Examples") ], swiftLanguageVersions: [.version("6")] )
  17. / / swift-tools-version: 6.0 import PackageDescription let package = Package(

    name: "Swift6Examples", platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ .library( name: "Swift6Examples", targets: ["Swift6Examples"] ) ], targets: [ .target(name: "Swift6Examples") ], swiftLanguageVersions: [.version("6")] )
  18. U p c o m i n g F e

    a t ur e s
  19. h t t ps :// g i t h u

    b . c o m / a p p l e / s w i f t - e v o l u t io n / b l ob / m a i n / p r o p o s a ls /0362- p i e ce m e a l - f u t u r e - f e a t ur e s . md
  20. // swift-tools-version: 6.0 import PackageDescription let package = Package( name:

    "UpcomingFeatures", products: [ .library( name: "UpcomingFeatures", targets: ["UpcomingFeatures"]), ], dependencies: [ ], targets: [ .target( name: "UpcomingFeatures", swiftSettings: [ .enableUpcomingFeature("InternalImportsByDefault") ] ) ] )
  21. B r e a k i ng ch a n

    ge s A q ui ck t o ur o f t he swift 6 Lan g uag e M o d e !
  22. h t t ps :// f o r u ms

    . swi ft . o r g / t / p r o gr e s s - t ow a r d - t h e - sw ift -6- l a ng u a ge - mo d e /68315
  23. C o n cu r r enc y ch e

    ck i ng SE-0337
  24. // swift-tools-version: 5.10 import PackageDescription let package = Package( name:

    "Swift6Examples", platforms: [.macOS(.v14)], products: [ .library( name: "Swift6Examples", targets: ["Swift6Examples"]), ], targets: [ .target( name: "Swift6Examples", dependencies: ["DependencyExample"], swiftSettings: [ .enableExperimentalFeature("StrictConcurrency") ] ) ] )
  25. I t hi nk m a n y p e

    o p l e b el ie v e y o u t ur n o n c o mp l et e c h e ck i n g t o ge t p r ep a r e d f o r S w if t 6. A nd , y e s , t h a t is t r ue ! B u t , I d o n o t t h i nk t his i s t he mo s t c o mp el l i ng r e a s o n t o d a y . Y o u tur n o n c o mp l e t e che ck i n g t o l e a r n how S wi ft c o n c u r r en c y a c tu a l l y w o r k s . h t t p s :// w ww . m a ssi c o tt e . o r g / c o m p l et e - ch e ck i ng M a tt M a ss ic o t t e @ m a tt iem @ m a s t o d o n . s o ci a l
  26. SE-0401 A c t o r i s o l

    a t io n p r o p er t y w r a p p e r s
  27. final class Model: ObservableObject { let name: String init(name: String

    = "Hello!") { self.name = name } } struct MyView: View { @StateObject private var model = Model() var body: some View { Text("Hello, \(model.name)") .onAppear { viewAppeared() } } func viewAppeared() { updateUI() } } @MainActor func updateUI() { /* do stuff here * / } Non-is ol a t ed
  28. final class Model: ObservableObject { let name: String init(name: String

    = "Hello!") { self.name = name } } struct MyView: View { @StateObject private var model = Model() var body: some View { Text("Hello, \(model.name)") .onAppear { viewAppeared() } } func viewAppeared() { updateUI() } } @MainActor func updateUI() { /* do stuff here * / } Iso la t e d t o t h e G lob al M ai n A c to r
  29. final class Model: ObservableObject { let name: String init(name: String

    = "Hello!") { self.name = name } } struct MyView: View { @StateObject private var model = Model() var body: some View { Text("Hello, \(model.name)") .onAppear { viewAppeared() } } func viewAppeared() { updateUI() } } @MainActor func updateUI() { /* do stuff here * / } Iso la t e d t o M ain Ac t o r
  30. final class Model: ObservableObject { let name: String init(name: String

    = "Hello!") { self.name = name } } struct MyView: View { @StateObject private var model = Model() var body: some View { Text("Hello, \(model.name)") .onAppear { viewAppeared() } } func viewAppeared() { updateUI() } } @MainActor func updateUI() { /* do stuff here * / } Iso la t e d t o M ain Ac t o r
  31. // swift-tools-version: 5.10 import PackageDescription let package = Package( name:

    "Swift6Examples", platforms: [.macOS(.v14)], products: [ .library( name: "Swift6Examples", targets: ["Swift6Examples"]), ], targets: [ .target( name: "Swift6Examples", dependencies: ["DependencyExample"], swiftSettings: [ .enableExperimentalFeature("StrictConcurrency"), .enableUpcomingFeature(“DisableOutwardActorInference") ] ) ] )
  32. // swift-tools-version: 6.0 import PackageDescription let package = Package( name:

    "Swift6Examples", platforms: [.macOS(.v14)], products: [ .library( name: "Swift6Examples", targets: ["Swift6Examples"]), ], targets: [ .target( name: "Swift6Examples", dependencies: ["DependencyExample"], swiftSettings: [ .enableExperimentalFeature("StrictConcurrency"), .enableUpcomingFeature("DisableOutwardActorInference"), .enableExperimentalFeature("RegionBasedIsolation"), .enableUpcomingFeature("IsolatedDefaultValues"), .enableUpcomingFeature("GlobalConcurrency"), .enableUpcomingFeature("InferSendableFromCaptures") ] ) ], swiftLanguageVersions: [.version("6")] )
  33. public extension XCTestCase { func assertInstancesAreDeallocated( _ instances: [AnyObject], line:

    UInt = #line, file: StaticString = #file ) { let instancesContainer = NSHashTable<AnyObject>.weakObjects() instances.forEach { instancesContainer.add($0) } addTeardownBlock { instancesContainer.allObjects.forEach { XCTAssertNil($0, file: file, line: line) } } } }
  34. public extension XCTestCase { func assertInstancesAreDeallocated( _ instances: [AnyObject], line:

    UInt = #line, file: StaticString = #file ) { let instancesContainer = NSHashTable<AnyObject>.weakObjects() instances.forEach { instancesContainer.add($0) } addTeardownBlock { instancesContainer.allObjects.forEach { XCTAssertNil($0, file: file, line: line) } } } }
  35. // swift-tools-version: 5.8 import PackageDescription let package = Package( name:

    "Swift6Examples", products: [ .library( name: "Swift6Examples", targets: ["Swift6Examples"]), ], targets: [ .testTarget( name: "Swift6ExamplesTests", dependencies: ["Swift6Examples"], swiftSettings: [ .enableUpcomingFeature("ConciseMagicFile") ] ) ] )
  36. #if hasFeature(ConciseMagicFile) / / In Swift 6 Language Mode XCTAssertEqual(#file,

    "Swift6ExamplesTests/Swift6ExamplesTests.swift") #else / / In Swift 5 Language Mode XCTAssertEqual( #file, "…/swift-6-swiftcraft/Tests/Swift6ExamplesTests/Swift6ExamplesTests.swift" ) #endif
  37. #if hasFeature(ConciseMagicFile) / / In Swift 6 Language Mode XCTAssertEqual(#file,

    "Swift6ExamplesTests/Swift6ExamplesTests.swift") #else / / In Swift 5 Language Mode XCTAssertEqual( #file, "…/swift-6-swiftcraft/Tests/Swift6ExamplesTests/Swift6ExamplesTests.swift" ) #endif
  38. // swift-tools-version: 5.7 import PackageDescription let package = Package( name:

    "Swift6Examples", platforms: [.macOS(.v14)], products: [ .library( name: "Swift6Examples", targets: ["Swift6Examples"]), ], targets: [ .target( name: "Swift6Examples", dependencies: ["DependencyExample"], swiftSettings: [ .enableUpcomingFeature("BareSlashRegexLiterals") ] ) ] )
  39. struct TestStructure { let firstClosure: ((String) -> Void)? let secondClosure:

    ((String, Int) - > Void)? init( firstClosure: ((String) -> Void)? = nil, secondClosure: ((String, Int) - > Void)? = nil ) { self.firstClosure = firstClosure self.secondClosure = secondClosure } }
  40. struct TestStructure { let firstClosure: ((String) - > Void)? let

    secondClosure: ((String, Int) -> Void)? init( firstClosure: ((String) - > Void)? = nil, secondClosure: ((String, Int) -> Void)? = nil ) { self.firstClosure = firstClosure self.secondClosure = secondClosure } }
  41. struct TestStructure { let firstClosure: ((String) - > Void)? let

    secondClosure: ((String, Int) -> Void)? init( firstClosure: ((String) - > Void)? = nil, secondClosure: ((String, Int) -> Void)? = nil ) { self.firstClosure = firstClosure self.secondClosure = secondClosure } } let a = TestStructure { a in print(a) }
  42. struct TestStructure { let firstClosure: ((String) - > Void)? let

    secondClosure: ((String, Int) -> Void)? init( firstClosure: ((String) - > Void)? = nil, secondClosure: ((String, Int) -> Void)? = nil ) { self.firstClosure = firstClosure self.secondClosure = secondClosure } } let a = TestStructure { a in print(a) } let b = TestStructure { a, b in print(a, b) } War n in g!
  43. // swift-tools-version: 5.10 import PackageDescription let package = Package( name:

    "Swift6Examples", platforms: [.macOS(.v14)], products: [ .library( name: "Swift6Examples", targets: ["Swift6Examples"]), ], targets: [ .target( name: "Swift6Examples", dependencies: ["DependencyExample"], swiftSettings: [ .enableUpcomingFeature(“ForwardTrailingClosures") ] ) ] )
  44. struct TestStructure { let firstClosure: ((String) - > Void)? let

    secondClosure: ((String, Int) -> Void)? init( firstClosure: ((String) - > Void)? = nil, secondClosure: ((String, Int) -> Void)? = nil ) { self.firstClosure = firstClosure self.secondClosure = secondClosure } } let a = TestStructure { a in print(a) } let b = TestStructure { a, b in print(a, b) } let c = TestStructure(secondClosure: { a, b in print(a, b) }) Ok! Er r o r ! Ok!
  45. I mp l i ci t O p en e

    xis t en t i a ls SE-0352
  46. Er r o r ! protocol WithSelfRequirement: Equatable {} func

    testOpenExistential(selfRequirementProtocol: WithSelfRequirement) { }
  47. protocol WithSelfRequirement: Equatable {} func requiresOpeningOfExistential<T: WithSelfRequirement>(openExistential: T) { }

    func testOpenExistential(selfRequirementProtocol: any WithSelfRequirement) { requiresOpeningOfExistential(openExistential: selfRequirementProtocol) }
  48. // swift-tools-version: 6.0 import PackageDescription let package = Package( name:

    "Swift6Examples", products: [ .library( name: "Swift6Examples", targets: ["Swift6Examples"]), ], targets: [ .target( name: "Swift6Examples", swiftSettings: [ .enableUpcomingFeature(“ImplicitOpenExistentials”) ] ) ] )
  49. SE-0383 d e p r e c a t e

    A p p l i c a t i o n m a i n
  50. import AppKit @NSApplicationMain final class MyApplication: NSResponder, NSApplicationDelegate { //

    .. . } import UIKit @UIApplicationMain final class MyApplication: UIResponder, UIApplicationDelegate { // .. . }
  51. import AppKit @NSApplicationMain final class MyApplication: NSResponder, NSApplicationDelegate { //

    .. . } import UIKit @UIApplicationMain final class MyApplication: UIResponder, UIApplicationDelegate { // .. . }
  52. import AppKit @main final class MyApplication: NSResponder, NSApplicationDelegate { //

    .. . } import UIKit @main final class MyApplication: UIResponder, UIApplicationDelegate { // .. . }
  53. // swift-tools-version: 5.10 import PackageDescription let package = Package( name:

    "Swift6Examples", products: [ .library( name: "Swift6Examples", targets: ["Swift6Examples"]), ], targets: [ .target( name: "Swift6Examples", swiftSettings: [ .enableUpcomingFeature("DeprecateApplicationMain") ] ) ] )
  54. // swift-tools-version: 5.9 import PackageDescription let package = Package( name:

    "Swift6Examples", products: [ .library( name: "Swift6Examples", targets: ["Swift6Examples"]), ], dependencies: [ ], targets: [ .target( name: "Swift6Examples", dependencies: ["DependencyExample"], swiftSettings: [ .enableExperimentalFeature("AccessLevelOnImport"), ] ), .target(name: "DependencyExample") ] )
  55. public import DependencyExample = = import DependencyExample internal import DependencyExample

    = = import DependencyExample Swi ft 6 la ngua ge mo de Swi ft 5 la ngua ge m ode
  56. // swift-tools-version: 6.0 import PackageDescription let package = Package( name:

    "Swift6Examples", products: [ .library( name: "Swift6Examples", targets: ["Swift6Examples"]), ], dependencies: [ ], targets: [ .target( name: "Swift6Examples", dependencies: ["DependencyExample"], swiftSettings: [ .enableExperimentalFeature("AccessLevelOnImport"), .enableUpcomingFeature("InternalImportsByDefault") ] ), .target(name: "DependencyExample") ] )
  57. #! /usr/bin/swift private import Foundation let fileManager = FileManager.default let

    currentDirectory = fileManager.currentDirectoryPath let swiftFiles = fileManager.enumerator(atPath: currentDirectory)? .compactMap { $0 as? String } .filter { $0.hasSuffix(".swift") } for file in swiftFiles ?? [] { let filePath = "\(currentDirectory)/\(file)" guard let content = try? String(contentsOfFile: filePath) else { continue } let updatedContent = content .replacingOccurrences(of: #"import (\w+)"#, with: "public import $1", options: .regularExpression) try? updatedContent.write(toFile: filePath, atomically: true, encoding: .utf8) } h t t ps :// w w w . po l p iel l a . d ev / s wi f t -6- i mp o r t - a c ce ss - l ev el # a d o p t i ng - t he se - c h a n ge s
  58. SE-0384 O bj - c F o r w a

    r d d e cl a r a t i o n s
  59. A l l br e a k i ng f

    e a tur e s SE-0274 F e a t ur e F l a g S wi ft 5.8 C o n c i s e M a gic F il e SE-0337 F e a t ur e F l a g S wi ft 5.6 S t r i c t c o n c ur r e nc y ch e ck i ng SE-0383 F e a t ur e F l a g S wi ft 5.10 D e p r e c a t e A p p l i c a t io n M a i n SE-0401 F e a t ur e F l a g S wi ft 5.9 D is a bl e O ut w a r d A c t o r I nf er en ce SE-0352 F e a t ur e F l a g S wi ft 6. o I mp l i ci t O p en E xis t e n t i a l s SE-0418 F e a t ur e F l a g S wi ft 6.0 I n f er S en d a b l e F r o m C a p tu r e s SE-0409 F e a t ur e F l a g S wi ft v er sio n 6.0 I n t e r n a l I m p o r t s B y D ef a ul t E xp e r i m en t a l f e a tu r e S wi ft 5.9 A c c e ss L e v e l O n I mpo r t SE-0384 F e a t ur e F l a g S wi ft 5.9 I m po r t O bj c F o r w a r d D e c l a r a t i o ns SE-0411 F e a t ur e F l a g S wi ft 5.10 I s o l a t ed D e f a ul t V a l u e s SE-0286 F e a t ur e F l a g S wi ft 5.8 F o r w a r d T r a i l i n g C l o s ur e s SE-0354 F e a t ur e F l a g S wi ft 5.8 B a r e S l a sh R e gex L i t er a ls SE-0412 F e a t ur e F l a g S wi ft v er sio n 5.10 G l o b a l C o ncur r enc y E xp e r i m en t a l f e a tu r e S wi ft 5.10 G l o b a l C o ncur r enc y
  60. T h a n k YOU! A n y q

    ue s t io n s ? Dow n loa d He l m Fin d me o n l i ne !