Programmiersprache Swift 5.9 führt Makros und ein Ownership-Konzept ein

Das neue Makrosystem von Swift bietet mehr als die Textbausteine in C/C++. Ownership bietet ein Konzept, um die Speicherverwaltung zu optimieren.

In Pocket speichern vorlesen Druckansicht 25 Kommentare lesen

(Bild: Paweł Kuźniar (unter der GFDL))

Lesezeit: 3 Min.
Inhaltsverzeichnis

Knapp sechs Monate nach Swift 5.8 ist Version 5.9 von Apples quelloffener Programmiersprache erschienen. Das aktuelle Release führt Makros ein und bekommt eine bidirektionale Anbindung an C++. Außerdem bringt sie erste Ansätze für das Ownership-Konzept, das als wesentlicher Bestandteil von Swift 6 vorgesehen ist.

Makros ergänzen Teile des Quellcodes vor dem Kompilieren mit zuvor definierten Inhalten. Swift orientiert sich bei der Implementierung eher an dem Makrosystem von Rust als den einfachen Makros in C oder C++, bei denen Makros einfache Platzhalter für Textbausteine sind, die vor dem Kompilieren ersetzt werden.

Swift 5.9 kennt zwei Arten von Markos: freistehende (freestanding) und angebundene (attached). Erstere sind mit # ausgezeichnet, und Swift ruft beim Kompilieren die Implementierung des Makros auf. Folgender Code verwendet das function()-Makro aus der Standard-Library von Swift:

func myFunction(){
  print ("Das Programm befindet sich in der Funktion \(#function)")
}

Das Makro ersetzt #function durch den Funktionsnamen, womit obiger Code "Das Programm befindet sich in der Funktion myFunction()" ausgibt.

Attached Macros helfen unter anderem bei der Arbeit mit Swift-Protokollen, wie folgender Codeausschnitt aus der Swift-Dokumentation zeigt, der das OptionSet-Protokoll mit einer Reihe von Konstanten automatisch befüllt:

// Makro-Variante 
@OptionSet<Int>
struct SundaeToppings {
  private enum Options: Int {
    case nuts
    case cherry
    case fudge
  }
}

// Manuelle Umsetzung ohne Makros
struct SundaeToppings: OptionSet {
  let rawValue: Int
  static let nuts = SundaeToppings(rawValue: 1 << 0)
  static let cherry = SundaeToppings(rawValue: 1 << 1)
  static let fudge = SundaeToppings(rawValue: 1 << 2)
}

Der Swift-Compiler ersetzt nicht einfach wie bei C oder C++ den Text des Makros, sondern ruft die jeweilige Implementierung auf.

(Bild: Swift-Dokumentation)

Eine weitere wichtige Neuerung ist die bidirektionale Interoperabilität mit C++, mit der sich externe Funktionen direkt aus Swift heraus verwenden lassen, wie ein Beispiel aus dem Swift-Blog zeigt, das die C++-Funktion

// Clang module 'PromptResponder'
#pragma once
#include <vector>

std::vector<std::string> generatePromptResponse(std::string prompt);

aus Swift aufruft:

import PromptResponder

let codeLines = 
  generatePromptResponse("Write Swift code that prints hello world")
  .map(String.init)
  .filter { !$0.isEmpty }

for line in codeLines {
  print(line)
}

Swift 5.9 führt zudem erste Ansätze eines Ownership-Konzepts für Variablen ein, das nicht so strikt und grundlegend ist wie in Rust, aber beim Optimieren der Speicherverwaltung helfen soll. Unter anderem entfällt damit die Notwendigkeit, die einzelnen Referenzen der Werte zu zählen. Der neue Operator consume erklärt die Lebenszeit einer Variable als beendet, sodass beim Zuweisen die alte Variable ihre Gültigkeit verliert. Nach der Anweisung

let b = consume a

enthält b den Wert von a, und anschließende Versuche, auf a zuzugreifen, lösen einen Fehler aus. Mit dem Operator lässt sich auch eine Variable mit

_ = consume a

explizit freigeben, ohne den Wert einer anderen zuzuweisen. Parameter können neuerdings als borrowing oder consuming deklariert werden. Außerdem führt Swift 5.9 nicht kopierbare Structs und Enums ein.

Weitere Neuerungen in Swift 5.9 wie Parameter Packs zum Übergeben einer flexiblen Zahl von Parametern und direkte Variablen-Zuweisungen in If- und Switch-Anweisungen lassen sich dem Swift-Blog entnehmen.

Zu der weiteren Roadmap der kommenden Hauptversion, die bereits in Swift 5.8 ihre Schatten vorausgeworfen hat, finden sich keine Angaben im Blogbeitrag.

(rme)