August 20, 2026·5 min read·engineeringswiftembeddedcompilers

Embedded Swift expands dynamic features with local costs

The Swift 6.4 preview broadens existential types, error handling and metatypes in Embedded Swift. Its design preserves a specialized compilation model while making more ordinary Swift code usable.

The August 20 preview of Embedded Swift improvements describes work coming in Swift 6.4 and available for evaluation in development snapshots. The changes expand support for existential types and metatypes, as well as untyped throwing functions. This is a preview of an upcoming release. Its examples describe the new capabilities without establishing that a previously installed stable toolchain has them.

The interesting design choice is how the project accounts for dynamic behavior. The announcement says that indirect calls and additional metadata can affect performance and code size, but those costs occur where the dynamic features are used. Code with tighter requirements can avoid the relevant constructs. That makes the expanding language subset easier to understand than a rule that every dynamic feature must always be excluded.

I appreciate Swift's value semantics and its attention to memory management. Those properties are part of why I find the language well designed. Embedded work interests me as a test of how much of that design can remain useful when runtime dependencies matter. I would assess these changes through the generated program and its actual requirements, rather than assuming that a familiar source construct has a negligible cost.

Existentials become more generally available

Previously, Embedded Swift accepted existential types only with an AnyObject constraint. The preview makes all any types available, including Any itself. That permits a value conforming to a protocol to sit behind an existential without requiring the value to be a class instance. The announcement demonstrates calling a protocol requirement through such a value.

A minimal example follows the same structure. It illustrates the preview capability and does not claim support in earlier Embedded Swift toolchains.

protocol Reading {
    func value() -> Int
}

struct FixedReading: Reading {
    func value() -> Int { 17 }
}

let reading: any Reading = FixedReading()
let result = reading.value()

There is still a fundamental restriction. Embedded Swift requires generic functions and types to become specialized, and it cannot call a generic function on an existential value in the cases described by the preview. General existential support therefore does not imply support for unspecialized generics. An ordinary protocol requirement and a generic method impose different compilation requirements.

That boundary is important when assessing an existing library. I would inspect what its protocol-based API actually calls after erasing a concrete type. A package may use an existential in a way the expanded subset permits, while another method still needs unsupported generic behavior. I would test the public operations the package needs instead of deciding compatibility from the presence of the any keyword alone.

Error handling inherits the existential change

The preview explains untyped throws as throwing a value of type any Error. Earlier Embedded Swift required a specific thrown error type. Generalizing existential support makes ordinary untyped throwing functions available too. This connects an application-facing language feature to the runtime representation it needs.

The announcement also warns that throwing an any Error value typically requires a heap allocation. It recommends typed throws for code that wants to avoid those allocations. Availability and suitability are therefore separate decisions. A function can become valid Embedded Swift while still using a representation that a particular target's memory policy rejects.

I would preserve that distinction in a library's documentation. If a package supports a constrained environment, I would want to know which error path it exercises and whether that path allocates. A successful happy-path example would not answer the question. Error handling belongs in the evaluation precisely because the resource constraints still apply when an operation fails.

The concurrency library also gains support for throwing operations, including throwing tasks and task groups. That improves consistency between asynchronous work and error handling in this compilation mode. I would still check the concurrency support required by the target platform before treating a source example as a complete deployment procedure.

Metatypes and parsing reduce porting differences

Embedded Swift previously permitted metatypes in narrow uses, such as specifying the type when binding raw memory. The preview describes complete metatype support, including existential metatype values. Its example stores a type conforming to an initialization protocol and constructs a value through that type. This makes a pattern available that previously required a different design in embedded code.

Floating-point parsing also becomes available following a Swift reimplementation of the parsing functionality. The announcement shows constructing a Double from text and handling the optional result. This is a useful example of compatibility work below the application API. Existing source can become usable when an implementation no longer depends on facilities absent from the embedded environment.

The Embedded Swift vision describes a language subset intended to retain Swift's ordinary semantics. Its compilation model specializes generic code at compile time and makes library implementations available to client builds. It also aims to emit metadata only when the used features need it. That explains why broadening the subset still requires boundaries around particular forms of runtime behavior.

The vision continues to exclude library evolution and the reflection APIs that require extensive metadata. Objective-C interoperability also depends on a runtime outside the intended model, while C and C++ interoperability remain part of the design. Those limits help define what a porting assessment must cover beyond the newly supported constructs.

I would evaluate this preview with a small dependency representative of the intended application. First I would identify which previously unsupported construct prevented compilation. Then I would check whether the new support resolves that exact case and inspect the resulting binary's requirements. I would include failing inputs where parsing or throwing behavior matters.

The preview mentions the PerformanceHints diagnostic group as a way to identify dynamic features relevant to code size and performance. I would use that feedback to locate decisions requiring review, then measure the application behavior I care about. A warning identifies a construct, while the target's constraints determine whether it is acceptable.

For a library intended to support both ordinary and Embedded Swift, I would document the minimum evaluated toolchain and any remaining language restrictions. The larger subset may reduce conditional implementations, but its specialization model still constrains which abstractions work. That is the compatibility information I would want before building a constrained application on top of the library.