Echtes Multi-Threading, Compile-Time-i18n und watchOS
Perry v0.4.0 ist das größte Release seit Projektbeginn. Drei Versionssprünge in einem Zyklus — v0.3.0 (i18n), v0.3.2 (watchOS), v0.4.0 (Multi-Threading) — und der Compiler selbst ist jetzt parallel. Hier ist alles, was ausgeliefert wurde.
Echtes Multi-Threading
Perry hat jetzt echte OS-Thread-basierte Parallelität. Keine Web Worker mit Serialisierungs-Overhead. Kein SharedArrayBuffer mit Atomics. Echte Threads — leichtgewichtige 8MB-Stack-OS-Threads, die nichts teilen und nichts kosten, wenn sie idle sind.
Das neue perry/thread-Modul bietet drei Primitive:
import { parallelMap, parallelFilter, spawn } from "perry/thread";
// Arbeit auf alle CPU-Kerne verteilen, Ergebnisse in Reihenfolge
const results = parallelMap(largeArray, (item) => heavyComputation(item));
// Parallel filtern
const matches = parallelFilter(data, (item) => expensiveCheck(item));
// Hintergrund-Thread starten, Promise erhalten
const result = await spawn(() => {
// läuft auf einem separaten OS-Thread
return computeExpensiveResult();
});parallelMap und parallelFilter erkennen automatisch die Anzahl der CPU-Kerne und verteilen das Eingabe-Array darauf. Bei kleinen Arrays wird Threading komplett übersprungen und synchron ausgeführt — kein Overhead für triviale Arbeitslasten.
spawn startet einen Hintergrund-OS-Thread und gibt ein Promise zurück. Das Ergebnis fließt über eine ausstehende Ergebnis-Warteschlange zurück, die während der Microtask-Verarbeitung geleert wird, sodass man es wie jede andere asynchrone Operation mit await behandeln kann.
Compile-Time-Sicherheit
Der wichtigste Teil ist nicht die API — es ist das, was der Compiler verhindert. Perry lehnt statisch Closures ab, die veränderbare Variablen erfassen:
let counter = 0;
// ✗ Kompilierfehler: Closure erfasst veränderbare Variable 'counter'
parallelMap(items, (item) => {
counter++; // zur Kompilierzeit abgelehnt
return item * 2;
});Kein geteilter veränderbarer Zustand bedeutet keine Data Races. Keine Locks, keine Mutexes, keine Atomics. Der Compiler erzwingt Thread-Sicherheit, bevor eine einzige Zeile Maschinencode erzeugt wird.
Unter der Haube
Jeder Worker-Thread bekommt seine eigene Speicher-Arena mit Drop-Bereinigung — keine GC-Koordination zwischen Threads. Werte werden über SerializedValue-Tiefkopie übertragen: kostenfrei für Zahlen, O(n) für Strings, Arrays und Objekte. Die Implementierung lebt in einer einzigen 1.120-Zeilen Rust-Datei (perry-runtime/src/thread.rs) und erforderte keine Änderungen am Garbage Collector.
Vergleich zu V8-Isolates, die separate Heaps pro Worker mit ~2MB Overhead benötigen. Perrys Threads sind einfach pthreads mit Arenas.
Parallele Compiler-Pipeline
Auch der Compiler selbst ist jetzt parallel. Modul-Codegen, Transform-Passes (JS-Imports, native Instanzen, Monomorphisierung) und nm-Symbolscannen laufen alle über alle CPU-Kerne via rayon. Kombiniert mit dem Cranelift 0.121 Upgrade (von 0.113 — acht Minor-Versionen mit Register-Allokation- und x64-Verbesserungen) ist die Kompilierung deutlich schneller.
Compile-Time i18n (v0.3.0)
Perrys Internationalisierungssystem hat null Zeremonie. String-Literale in UI-Widgets werden automatisch als lokalisierbare Schlüssel behandelt. Übersetzungsdateien sind flache JSON-Dateien in einem locales/-Verzeichnis. Alle Validierung erfolgt zur Kompilierzeit.
// locales/en.json
{ "greeting": "Hello, {name}!" }
// locales/de.json
{ "greeting": "Hallo, {name}!" }
// Dein Code — verwende Strings einfach normal
Button({ title: "greeting", action: () => {} })Der Compiler validiert alles: fehlende Übersetzungen, Parameter-Unstimmigkeiten, Plural-Fehler. Übersetzungen werden als eingebettete 2D-String-Tabelle in die Binärdatei eingebettet, mit nahezu null Runtime-Lookup — kein JSON-Parsing beim Start.
Was enthalten ist
- CLDR-Pluralregeln für 30+ Locales mit
.one/.other/.few/.many/.zero/.two-Suffixen - Format-Wrapper:
Currency,Percent,ShortDate,LongDate,FormatNumber,FormatTime,Raw - Native Locale-Erkennung auf allen Plattformen:
CFLocaleCopyCurrent(macOS/iOS),GetUserDefaultLocaleName(Windows),system_property_get(Android),LANG/LC_ALL(Linux) perry i18n extractCLI: scannt TS/TSX-Dateien, generiert und aktualisiert Locale-JSON-Gerüste- Plattform-native Ressourcengenerierung: iOS
.lprojund Androidvalues-xx/Verzeichnisse import { t } from "perry/i18n"für die Lokalisierung von Nicht-UI-Strings
Konfiguration in perry.toml:
[i18n]
locales = ["en", "de", "ja", "es", "fr"]
default_locale = "en"
currencies = { USD = "en", EUR = "de", JPY = "ja" }Native watchOS-Apps (v0.3.2)
Perry kompiliert jetzt für watchOS — das 9. Kompilierungsziel. Das ist kein Wrapper oder eine Companion-App. Es ist eine eigenständige watchOS-Binärdatei mit einer nativen SwiftUI-Oberfläche.
Der watchOS-Renderer verwendet einen datengesteuerten Ansatz: Perry erstellt einen UI-Baum über perry_ui_* FFI-Aufrufe, und eine mitgelieferte PerryWatchApp.swift fragt den Baum ab und rendert SwiftUI-Views reaktiv. 15 Widget-Typen werden unterstützt, mit Stubs für nicht unterstützte.
# Für watchOS kompilieren
perry compile main.ts --target watchos
# Auf Apple Watch Simulator ausführen
perry run watchos
# Signierung für watchOS einrichten
perry setup watchosDer vollständige Ablauf funktioniert: perry setup watchos teilt App Store Connect-Anmeldedaten mit iOS, perry run watchos erkennt automatisch Apple Watch-Simulatoren, und perry publish watchos reicht beim App Store ein.
Damit steigt die Gesamtzahl der Widget-Ziele auf vier: iOS (WidgetKit), Android (Glance), watchOS (WidgetKit) und Wear OS (Tiles). Jedes hat sein eigenes Compile-Target und Codegen-Backend.
Audio- & Kamera-APIs
Zwei neue Hardware-APIs werden in diesem Release ausgeliefert:
Audio-Aufnahme (perry/system)
Plattformübergreifende Audio-Aufnahme mit A-bewerteter dB(A)-Messung:
import { audioStart, audioStop, audioGetLevel, audioGetWaveformSamples } from "perry/system";
audioStart();
const level = audioGetLevel(); // dB(A) mit EMA-Glättung
const waveform = audioGetWaveformSamples(); // 256-Sample Ringpuffer
audioStop();Plattform-Backends: AVAudioEngine (macOS/iOS), AudioRecord über JNI (Android), PulseAudio (Linux), WASAPI (Windows), getUserMedia + AnalyserNode (Web).
Kamera-Aufnahme (perry/ui)
Native Kamera-Vorschau mit pixelgenauer Farbentnahme (iOS):
import { CameraView, cameraStart, cameraSampleColor } from "perry/ui";
cameraStart();
const [r, g, b] = cameraSampleColor(x, y); // 5x5 MittelwertbildungÖkosystem-Pakete
Zwei neue First-Party-Pakete:
- perry/push — Push-Notification-Bindings für iOS/macOS: Berechtigungsanfragen, APNs-Token-Abruf, Badge-Zähler. Android-Stub mit FCM geplant.
- perry/storekit — StoreKit 2 In-App-Kauf-Bindings: Produktladen, Käufe mit JWS-Quittungen, Abonnement-Prüfung, Wiederherstellung und Transaktions-Listener.
Beide folgen derselben Architektur: TypeScript-Deklarationen → Rust FFI-Crate → Swift-Bridge. Als Abhängigkeit installieren, Funktionen importieren, Ergebnisse mit await abwarten. Der Compiler kümmert sich um alle nativen Bridges.
Infrastruktur
- Cranelift 0.113 → 0.121 — acht Minor-Versionen mit Register-Allokation, x64-Fixes und Stack-Slot-Alignment-Verbesserungen
- Windows-Funktionsaufteilung — teilt automatisch Funktionen mit 50+ Anweisungen in Fortsetzungen auf, um Cranelift-Codegen-Probleme unter Windows zu umgehen
- Selektives Modul-Variablen-Laden — lädt nur referenzierte Modul-Level-Variablen beim Funktionseintritt, reduziert die Windows-Binärgröße um 26 %
- Array.sort() Upgrade — von O(n²) Insertion Sort zu O(n log n) TimSort-Hybrid
- perry run android — vollständige APK-Build-Pipeline: Kompilieren, Gradle-Projektgenerierung, assembleDebug, Installieren, Starten
- Benutzerdefinierte Info.plist-Einträge —
[ios.info_plist]in perry.toml für Datenschutzbeschreibungen, URL-Schemata, Hintergrundmodi
In Zahlen
- Version: 0.2.197 → 0.4.0 (drei große Meilensteine)
- Kompilierungsziele: 8 → 9 (watchOS hinzugefügt)
- Widget-Ziele: 1 → 4 (iOS, Android, watchOS, Wear OS)
- Neue Crates: perry-ui-watchos, perry-codegen-glance, perry-codegen-wear-tiles
- Neue Dokumentation: Threading (4 Seiten), i18n (4 Seiten), watchOS, erweiterte Widget-Docs (3 → 8 Seiten)
- perry/thread Implementierung: 1.120 Zeilen Rust, null Änderungen am GC
Was kommt als Nächstes
Die Threading-Grundlage eröffnet vieles: parallele HTTP-Anfrageverarbeitung, gleichzeitige Dateioperationen und rechenintensive Arbeitslasten, die zuvor durch Single-Threaded-Ausführung blockiert waren. Auf der Sprachseite bleibt volle Regex-Unterstützung die größte Lücke, und die perry/ui-Erweiterung (Drag and Drop, Barrierefreiheit, DatePicker) geht weiter.
Verfolge den Fortschritt auf GitHub, lies die Dokumentation auf docs.perryts.com, oder sieh dir die Roadmap für das vollständige Bild an.
Gefällt dir dieser Beitrag? Hol dir den nächsten.
Kurze Notizen zu Perry-Releases und woran wir als Nächstes arbeiten.
Ein paar E-Mails im Monat. Jederzeit abbestellbar.