Working with Embedded Swift for WebAssembly (for web app development) involves facing numerous limitations that seem unnecessary in the WebAssembly scenario.

String

String is a significant component that adds megabytes to the final binary, which is why it has been removed. I created a custom String implementation with UTF-16 under the hood (code name U16String), as suggested by Max Desiatov. I am wondering if it is possible to implement StringInterpolation for it, but it seems to be made at the compiler level only for String.

Protocols

Cannot use a value of protocol any MyProtocol type in Embedded Swift.

Protocols are partially functional. I assume that if full functionality were restored, the compiler would generate much more code to handle all possible cases. However, I don't think this would contribute significantly to the overall size in megabytes.

Codable

'Codable' is unavailable: unavailable in Embedded Swift.

Does it also add too much to the final binary? It would be great to have Encodable and Decodable protocols available, so custom encoders/decoders could be written.

Concurrency

Is it available in any form?

I understand these limitations from the perspective of microcontrollers where every kilobyte matters, and Embedded Swift was actually made for that.

For WebAssembly, it is also crucial to minimize the final binary size. My current wasm binary using Embedded Swift is under 150KB, which is impressive, especially compared to a full Swift implementation which is about 10-13MB. However, I believe that for WebAssembly, we still need a full version of Swift with the ability to disable large features like String support to reduce the final binary size dramatically to about 1-2MB, while retaining most of Swift's powerful features.

For me, Swift for WebAssembly development is akin to development for iOS/tvOS/macOS targets—it is client-side code. It would be great to be able to reuse most components of client-side code across platforms. However, the absolute minimum is having models (codable structs), which seems impossible while Codable is completely unavailable.

2 Likes

This should be possible, can you share some code (ideally as a package) that we can look at?

"any" types (existentials) are disabled in Embedded Swift because they require the use of runtime type metadata which is intentionally not available in Embedded Swift.

  • Remove or reduce the amount of implicit runtime calls. Specifically, runtime calls supporting heavyweight runtime facilities (type metadata lookups, generic instantiation) should not exist in Embedded Swift programs. Lightweight runtime calls (e.g. refcounting) are permissible but should only happen when the application uses a language feature that needs them (e.g. refcounted types).

That said, we recognize that existentials are an important way to opt into dynamic dispatch. Kuba, Joe, myself, Erik, and a couple others have discussed what it might mean to bring existentials back into Embedded Swift.

I think folks are a bit busy for the next couple weeks but this is a great topic to discuss in the new Development > Embedded subcategory of the forums.

One direction I personally would love to see is a lifetime bound (~Escapable) existential which would work for both Embedded and full Swift similar to Rust's dyn Trait.

This is because Codable requires the use of existentials. Serde like macros might be a solution.

Not yet, but this is actually something we want to enable for Embedded Swift but requires design work that hasn't yet occurred.

Embedded systems have a couple of dominant work-loops / concurrency models and it's important we find a solution that is pluggable and suits a variety of needs.

3 Likes

Also I hope you dont mind, I've moved this conversation from Development > Core Libraries to Development > Embedded.

3 Likes