Что нового в Swift 6?

от автора

Swift 6 — это важное обновление языка программирования Swift, разработанного Apple. Данная версия включает множество нововведений и улучшений, особенно в области параллелизма. В этом документе мы рассмотрим основные изменения и их влияние на разработчиков, опираясь на официальную документацию Apple.

Пожалуйста, обратите внимание, что все упомянутые изменения являются актуальными на момент выхода Swift 6, и в будущем могут появиться новые обновления и дополнения. Рассмотрим основные нововведения Swift 6, начиная с изменений в доменах изоляции и параллелизма.

Полный параллелизм включен по умолчанию

Swift 6 включает в себя множество обновлений, касающихся параллелизма, и команда разработчиков может гордиться своими достижениями. Самое значительное изменение заключается в том, что полная проверка параллельности теперь включена по умолчанию. Это изменение может потребовать некоторых корректировок в вашем коде, что неудивительно, так как в предыдущих версиях эта функция была опциональной, чтобы дать разработчикам время адаптироваться к изменениям.

Swift 6 улучшает проверку параллелизма, устраняя множество ложных предупреждений о гонках данных, которые присутствовали в версии 5.10. Внесены также ряд целевых изменений, которые делают параллелизм легче для освоения.

Одним из крупнейших нововведений является SE-0414, который вводит домены изоляции, позволяющие компилятору убедительно доказать, что различные части вашего кода могут выполняться параллельно.

В основе этого изменения лежит существующая концепция отправляемости (sendability). Тип Sendable — это такой тип, который можно безопасно передавать в параллельной среде. Это могут быть типы значений, такие как структуры, финальные классы с константными свойствами, акторы, которые автоматически защищают свое изменяемое состояние, и многое другое.

Ранее компилятор Swift был очень строг: если у вас было значение, не поддающееся отправке (non-sendable), и вы пытались передать его другому актору, вы получали предупреждение о проверке параллельности. Например, хотя тела представлений SwiftUI выполняются на основном акторе, сами представления SwiftUI этого не делают, что может легко вызвать ложные предупреждения компилятора.

Рассмотрим следующий код:

class User {     var name = "Anonymous" }      struct ContentView: View {     var body: some View {         Text("Hello, world!")             .task {                 let user = User()                 await loadData(for: user)             }     }          func loadData(for user: User) async {         print("Loading data for \(user.name)…")     } } 

До Swift 6 вызов функции loadData() вызвал бы предупреждение: «передача аргумента типа ‘User’ за пределы изолированного контекста основного актора может вызвать гонки данных.»

В Swift 6 это предупреждение исчезает: Swift теперь определяет, что код не представляет проблемы, так как user не используется одновременно из нескольких мест, и не выдаст предупреждение. Компилятор анализирует поток программы и определяет, что это безопасно.

Это изменение означает, что объекты, пригодные для отправки, теперь либо соответствуют протоколу Sendable, либо не нуждаются в этом, потому что компилятор может доказать, что они используются безопасно — это значительное улучшение параллелизма для разработчиков, возможно благодаря передовым разработкам компилятора.

Также внесены множество других, более мелких улучшений, включая:

  • SE-430 добавляет новое ключевое слово sending, когда нужно отправить значения между доменами изоляции.

  • SE-0423 улучшает поддержку параллельности при работе с фреймворками Objective-C.

  • SE-0420 позволяет создавать асинхронные функции, изолированные тем же актором, что и их вызывающий код.

Устаревшие функции

Некоторые изменения были доступны в предыдущих версиях Swift, но скрыты за флажками функций. Например, SE-0401 удаляет функцию, введенную в Swift 5.5: вывод акторов для оберток свойств.

Ранее любой структурный или классовый тип, использующий обертку свойства с @MainActor для его обернутого значения, автоматически становился @MainActor. Это позволило @StateObject и @ObservedObject передавать «main-actor-ness» на представления SwiftUI, которые их используют.

@MainActor class ViewModel: ObservableObject {     func authenticate() {         print("Authenticating…")     } }  @MainActor struct LogInView: View {     @StateObject private var model = ViewModel()          var body: some View {         Button("Hello, world", action: startAuthentication)     }          func startAuthentication() {         model.authenticate()     } } 

Ранее @MainActor присваивался бы всему представлению из-за его свойства @StateObject.

Строгий параллелизм для глобальных переменных

Еще одно старое изменение, теперь включенное в Swift 6, — SE-0412, требующее, чтобы глобальные переменные были безопасны в параллельных средах. Это касается как глобальных переменных в проекте, так и статических переменных в типах.

Примеры:

var gigawatts = 1.21  struct House {     static var motto = "Winter is coming" } 

Эти данные могут быть доступны в любое время, что делает их небезопасными. Чтобы решить эту проблему, нужно либо преобразовать переменную в sendable-константу, либо ограничить ее глобальным актором, например, @MainActor, либо, если нет других вариантов, пометить её как nonisolated.

struct XWing {     @MainActor     static var sFoilsAttackPosition = true }      struct WarpDrive {     static let maximumSpeed = 9.975 }      @MainActor var idNumber = 24601  // Не рекомендуется, если вы не уверены, что это безопасно nonisolated(unsafe) var britishCandy = ["Kit Kat", "Mars Bar", "Skittles", "Starburst", "Twix"] 

Изменения в значениях по умолчанию для функций

Другое изменение, которое теперь включено, — SE-0411, которое изменяет значения по умолчанию для функций так, чтобы они имели ту же изоляцию, что и сама функция.

@MainActor class Logger {}  @MainActor  class DataController {     init(logger: Logger = Logger()) {} } 

Поскольку и DataController, и Logger ограничены основным актором, Swift теперь считает создание Logger() также ограниченным основным актором, что имеет смысл.

Новый метод count(where:)

SE-0220 ввел новый метод count(where:), который выполняет эквивалент filter() и count в одном проходе. Это экономит создание нового массива, который сразу же отбрасывается, и предоставляет ясное и лаконичное решение распространенной проблемы.

Пример:

let scores = [100, 80, 85] let passCount = scores.count { $0 >= 85 }

Этот метод доступен для всех типов, которые соответствуют Sequence, так что вы можете использовать его для множеств и словарей.

Типизированные выбросы ошибок (Typed Throws)

SE-0413 ввел возможность указать, какие именно типы ошибок может выбросить функция, известную как «typed throws». Это решает неудобство с ошибками в Swift: раньше требовалось общее выражение catch, даже если вы специально обрабатывали все возможные ошибки.

Пример:

enum CopierError: Error {     case outOfPaper }  struct Photocopier {     var pagesRemaining: Int          mutating func copy(count: Int) throws(CopierError) {         guard count <= pagesRemaining else {             throw CopierError.outOfPaper         }              pagesRemaining -= count     } }  do {     var copier = Photocopier(pagesRemaining: 100)     try copier.copy(count: 10) } catch CopierError.outOfPaper {     print("Please refill the paper") } 

Итерация пакета (Pack Iteration)

SE-0408 вводит итерацию по пакетам, что добавляет возможность обхода параметров пакета, введенных в Swift 5.9. Это позволяет, например, сравнивать кортежи любой арности всего в нескольких строках кода:

func == <each Element: Equatable>(lhs: (repeat each Element), rhs: (repeat each Element)) -> Bool {     for (left, right) in repeat (each lhs, each rhs) {         guard left == right else { return false }     }     return true } 

Операции с элементами коллекций

SE-0270 вводит различные новые методы для работы с коллекциями, такие как перемещение или удаление нескольких элементов, которые не являются смежными. Это изменение поддерживается новым типом RangeSet.

Пример:

struct ExamResult {     var student: String     var score: Int }      let results = [     ExamResult(student: "Eric Effiong", score: 95),     ExamResult(student: "Maeve Wiley", score: 70),     ExamResult(student: "Otis Milburn", score: 100) ]  let topResults = results.indices { student in     student.score >= 85 }  for result in results[topResults] {     print("\(result.student) scored \(result.score)%") } 

Модификаторы уровня доступа для объявлений импорта

SE-0409 добавляет возможность отмечать объявления импорта модификаторами уровня доступа, такими как private import SomeLibrary. Это помогает разработчикам библиотек избегать случайного утечки собственных зависимостей.

Пример:

// Внутренняя библиотека public struct BankTransaction {     // код здесь }  // Основная библиотека public func sendMoney(from: Int, to: Int) -> BankTransaction {     // обработка перевода денег     return BankTransaction() }  // Основное приложение import BankingLibrary sendMoney(from: 123, to: 456) 

С Swift 6 можно использовать internal import Transactions в основной библиотеке, чтобы ограничить видимость.

Улучшения для noncopyable типов

Несколько улучшений для noncopyable типов, введенных в Swift 5.9. Noncopyable типы позволяют создавать типы с уникальным владением, которые можно передавать, используя заимствование или потребление.

Пример:

struct Message: ~Copyable {     var agent: String     private var message: String          init(agent: String, message: String) {         self.agent = agent         self.message = message     }          consuming func read() {         print("\(agent): \(message)")     } }      func createMessage() {     let message = Message(agent: "Ethan Hunt", message: "You need to abseil down a skyscraper for some reason.")     message.read() }      createMessage() 

В Swift 6, все структуры, классы, перечисления, параметры обобщений и протоколы автоматически соответствуют новому протоколу Copyable, если явно не отказаться от него, используя ~Copyable.

Типы 128-битных целых чисел

SE-0425 вводит Int128 и UInt128. Эти типы работают так же, как и другие целочисленные типы в Swift.

Пример:

let enoughForAnybody: Int128 = 170_141_183_460_469_231_731_687_303_715_884_105_727

Протокол BitwiseCopyable

SE-0426 вводит новый протокол BitwiseCopyable, который позволяет компилятору создавать более оптимизированный код для соответствующих типов.

Пример:

@frozen public enum CommandLine: ~BitwiseCopyable { } 

Эти улучшения помогают делать noncopyable типы более естественными в использовании и повышают производительность кода.

Swift 6 приносит значительные улучшения, особенно в доменах параллелизма, делая ее более доступной и понятной для разработчиков. Новые возможности, такие как полная проверка параллелизма по умолчанию, домены изоляции и усовершенствованное понятие sendability, упрощают написание безопасного и эффективного кода. Большая часть изменений направлена на адаптацию разработчиков к новым требованиям и использованию мощных функций языка Swift для создания высокопроизводительных приложений. 

Полагаю что это только начало, начало огромного будущего нами всеми любимого языка.


ссылка на оригинал статьи https://habr.com/ru/articles/820961/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *