What's New in Swift 6.2

Swift 6.2 introduces several enhancements aimed at improving concurrency, generics, error handling, and performance. Here’s a summary of the key features that you might use as developers, I’ll ignore complicated behind-the-scene features:

SE-0470 Global-actor isolated conformances

This proposal introduces isolated conformances which are conformances whose use is restricted to a particular global actor, enforced statically by the compiler and without any boilerplate. The following defines a main-actor-isolated conformance of MyModelType to Equatable:

@MainActor
class MyModelType: @MainActor Equatable {
  var name: String

  init(name: String) {
    self.name = name
  }

  static func ==(lhs: MyModelType, rhs: MyModelType) -> Bool { 
    lhs.name == rhs.name
  }
}

Any attempt to use this conformance outside of the main actor will result in a compiler error:

/*nonisolated*/ func hasMatching(_ value: MyModelType, in modelValues: [MyModelType]) -> Bool {
  // error: cannot use main-actor-isolated conformance of 'MyModelType' to 'Equatable' in
  // non-isolated function.
  return modelValues.contains(value)
}

SE-0469 Task Naming

This proposal introduces several new APIs to name Swift Tasks for the purposes of identifying tasks in a human-readable way. These names can then be used to identify tasks by printing their names, programatically inspecting the name property, or by tools which dump and inspect tasks–such as debuggers, swift-inspect or others.

Naming tasks is only allowed during their creation, and modifying names is not allowed.

let getUsers = Task(name: "Get Users") {
	await users.get(accountID)
}

Names are arbitrary user-defined strings, which may be computed at runtime because they often contain identifying information such as the request ID or similar runtime information.

let getUsers = Task("Get Users for \(accountID)") {
	await users.get(accountID)
}

SE-0453 InlineArray, a fixed-size array

It’s important to understand that Array is a heap allocated growable data structure which can be expensive and unnecessary in some situations.

Array is a very general purpose array collection that can suit almost any need, but it is always heap allocated, automatically resizable, and introduces retain/release traffic. These implicit allocations are becoming more and more of a bottleneck, especially in embedded domains where there might not be a lot of memory for many allocations or even heap allocations at all.

Swift should be able to provide developers a safe API to have an ordered list of homogeneous items on the stack, allowing for things like indexing, iteration, and many other collection utilities.

This proposal introduces a new top level type, InlineArray, to the standard library which is a fixed-size contiguously inline allocated array. It will be stack allocated most of the time, but as a class property member it will be inline allocated on the heap with the rest of the properties. InlineArray will never introduce an implicit heap allocation just for its storage alone.

func complexAlgorithm() {
  // This is a stack allocation, no 'malloc's or reference counting here!
  let elements: InlineArray<4, Int> = [1, 2, 3, 4]

  for i in elements.indices {
    compute(elements[i]) // OK
  }
}

SE-0452 Integer Generic Parameters

Generic types can now be parameterized by integer parameters, declared using the syntax let : Int inside of the generic parameter angle brackets:

struct Vector<let count: Int, Element> {
    /* * */
}

A generic type with integer parameters can be instantiated using literal integer arguments:

struct Matrix4x4 {
    var matrix: Vector<4, Vector<4, Double>>
}

Or it can be instantiated using integer generic parameters from the surrounding generic environment:

struct Matrix<let columns: Int, let rows: Int> {
    var matrix: Vector<columns, Vector<rows, Double>>
}

Beyond inline storage sizes, there are other use cases for carrying integers in type information, such as to represent an operation with a particular input or output size. Carrying this information in types can allow for APIs with stronger static guarantees that chains of operations match in the number of elements they consume or produce.