Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2024 Developer ToolsSwift

WWDC24 · 30 min · Developer Tools / Swift

What’s new in Swift

Join us for an update on Swift. We’ll briefly go through a history of Swift over the past decade, and show you how the community has grown through workgroups, expanded the package ecosystem, and increased platform support. We’ll introduce you to a new language mode that achieves data-race safety by default, and a language subset that lets you run Swift on highly constrained systems. We’ll also explore some language updates including noncopyable types, typed throws, and improved C++ interoperability.

Watch at developer.apple.com ↗

Transcript all transcripts

Chapters

Code shown on screen · 25 snippets

Swift Build bash · at 9:15 ↗
swift build
Inspecting the build output bash · at 9:20 ↗
file .build/debug/CatService
Run the REST API service bash · at 9:24 ↗
.build/debug/CatService
Make a request to REST API service bash · at 9:30 ↗
curl localhost:8080/api/emoji
Install the Fully static Linux SDK for Swift bash · at 9:45 ↗
swift sdk install ~/preview-static-swift-linux-0.0.1.tar.gz
Swift build command flag to cross compile bash · at 10:18 ↗
swift build --swift-sdk aarch64-swift-linux-musl
Inspecting the build output bash · at 10:30 ↗
file .build/debug/CatService
Copy the service over to our Linux server and run it bash · at 10:35 ↗
scp .build/debug/CatService demo-linux-host:~/CatService
./CatService
Make a request to REST API service from macOS to Linux bash · at 10:45 ↗
curl demo-linux-host:8080/api/emoji
Swift Testing - Declare a test function swift · at 13:50 ↗
// Swift Testing 

import Testing

@Test
func rating() {
    let video = Video(id: 2, name: "Mystery Creek")
    #expect(video.rating == "⭐️⭐️⭐️⭐️")
}
Swift Testing - Customize a test’s name swift · at 13:55 ↗
// Swift Testing 

import Testing

@Test("Recognized rating")
func rating() {
    let video = Video(id: 2, name: "Mystery Creek")
    #expect(video.rating == "⭐️⭐️⭐️⭐️")
}
Swift Testing - Organize test function with tags swift · at 14:13 ↗
// Swift Testing 

import Testing

@Test("Recognized rating",
       .tags(.critical))
func rating() {
    let video = Video(id: 2, name: "Mystery Creek")
    #expect(video.rating == "⭐️⭐️⭐️⭐️")
}
Swift Testing - Parameterize test with arguments swift · at 14:19 ↗
// Swift Testing 

import Testing

@Test("Recognized rating",
       .tags(.critical),
       arguments: [
           (1, "A Beach",       "⭐️⭐️⭐️⭐️⭐️"),
           (2, "Mystery Creek", "⭐️⭐️⭐️⭐️"),
       ])
func rating(videoId: Int, videoName: String, expectedRating: String) {
    let video = Video(id: videoId, name: videoName)
    #expect(video.rating == expectedRating)
}
Noncopyable types swift · at 17:50 ↗
struct File: ~Copyable {
  private let fd: CInt
  
  init(descriptor: CInt) {
    self.fd = descriptor
  }

  func write(buffer: [UInt8]) {
    // ...
  }

  deinit {
    close(fd)
  }
}
Noncopyable types swift · at 18:12 ↗
guard let fd = open(name) else {
  return
}
let file = File(descriptor: fd)
file.write(buffer: data)
Noncopyable types swift · at 18:42 ↗
struct File: ~Copyable {
  private let fd: CInt
  
  init?(name: String) {
    guard let fd = open(name) else {
      return nil
    }
    self.fd = fd
  }

  func write(buffer: [UInt8]) {
    // ...
  }

  deinit {
    close(fd)
  }
}
C++ Interoperability cpp · at 22:29 ↗
struct Person {
  Person(const Person&) = delete;
  Person(Person &&) = default;
  // ...
};
C++ Interoperability swift · at 22:34 ↗
struct Developer: ~Copyable {
    let person: Person
    init(person: consuming Person) {
      self.person = person
    }
}

let person = Person()
let developer = Developer(person: person)
C++ Interoperability swift · at 22:40 ↗
struct Developer: ~Copyable {
    let person: Person
    init(person: consuming Person) {
      self.person = person
    }
}

let person = Person()
let developer = Developer(person: person)
person.printInfo()
Untyped throws swift · at 23:43 ↗
enum IntegerParseError: Error {
  case nonDigitCharacter(String, index: String.Index)
}

func parse(string: String) throws -> Int {
  for index in string.indices {
    // ...
    throw IntegerParseError.nonDigitCharacter(string, index: index)
  }
}

do {
  let value = try parse(string: "1+234")
}
catch let error as IntegerParseError {
  // ...
}
catch {
   // error is 'any Error'
}
Typed throws swift · at 24:19 ↗
enum IntegerParseError: Error {
  case nonDigitCharacter(String, index: String.Index)
}

func parse(string: String) throws(IntegerParseError) -> Int {
  for index in string.indices {
    // ...
    throw IntegerParseError.nonDigitCharacter(string, index: index)
  }
}

do {
  let value = try parse(string: "1+234")
}
catch {
   // error is 'IntegerParseError'
}
Typed throws - any and Never error types swift · at 24:39 ↗
func parse(string: String) throws -> Int {
  //...
}

func parse(string: String) throws(any Error) -> Int {
  //...
}



func parse(string: String) -> Int {
  //...
}

func parse(string: String) throws(Never) -> Int {
  //...
}
Passing a NonSendable reference across actor isolation boundaries swift · at 28:02 ↗
class Client {
  init(name: String, balance: Double) {}
}

actor ClientStore {
  static let shared = ClientStore()
  private var clients: [Client] = []
  func addClient(_ client: Client) {
    clients.append(client)
  }
}

@MainActor
func openAccount(name: String, balance: Double) async {
  let client = Client(name: name, balance: balance)
  await ClientStore.shared.addClient(client)
}
Atomic swift · at 28:52 ↗
import Dispatch
import Synchronization 

let counter = Atomic<Int>(0)

DispatchQueue.concurrentPerform(iterations: 10) { _ in
  for _ in 0 ..< 1_000_000 {
    counter.wrappingAdd(1, ordering: .relaxed)
  }
}

print(counter.load(ordering: .relaxed))
Mutex swift · at 29:21 ↗
import Synchronization

final class LockingResourceManager: Sendable {
  let cache = Mutex<[String: Resource]>([:])
  
  func save(_ resource: Resource, as key: String) {
    cache.withLock {
      $0[key] = resource
    }
  }
}

Resources