SwiftTLS – A TLS implementation in Swift
github.com
github.com
The point of my post wasn't to criticize SwiftTLS, per se, but rather to make a larger point that supporting asynchronous I/O will never become substantially easier unless and until languages provide the correct primitives. Case in point: try to refactor SwiftTLS (which otherwise may be a laudable TLS implementation) to support Swift's async/await proposal. All the headaches and compromises will say much more about the viability of async/await than about the implementation quality of SwiftTLS. Nonetheless, it's the end product (SwiftTLS, etc) that will be bear the blame for the added complexity (or lack thereof if they abstain from supporting the model).
Alternatively, you need to make one or the other a 2nd class citizen (e.g. write the core implementation using async/await and make the synchronous API a wrapper), making that aspect of the implementation substandard in the eyes of your library users.
There are alternative language primitives, like asymmetric stackful coroutines, that provide much better semantics. You can continue sharing all your code using the same function composition patterns because there's no bifurcation in the function space--a coroutine looks and behaves and is invoked like any other function.
Stackful coroutines aren't memory efficient if you try to maintain compatibility with traditional C ABIs, especially on 32-bit platforms. To reliably run C code musl libc, for example, has minimum stack sizes of 80KB. By contrast, a stackful coroutine in Lua has an initial allocation size (including stack) of less than 300 bytes, and the stack is dynamically resized as needed. So stackful coroutines aren't a good fit for Rust which emphasize seamless backward compatibility with existing C code.
But for a language like Swift I think the designers could have gone the other way[1], and it's a shame they've committed themselves to a language primitive that is a dead-end and only as popular as it is because of extrinsic limitations--Rust's is backward compatibility with C, for JavaScript and Python it's the fact that the existing engines intertwine the C stack with the languages logical stack. (For use cases where async/await may be a preferable paradigm, e.g. code documentation or ability to block suspension of the caller, async/await can be implemented cleanly and cheaply atop the lower-level primitive. Stackful coroutines are a strictly more elegant and capable primitive.)
People debate these issues endlessly and many people would disagree with me. But my point is that the real proof of my argument can be seen in the difficulty of authoring and maintaining real world libraries like SwiftTLS. Forget abstract arguments--look at the concrete use cases and not anecdotes or proofs-of-concept. The async/await world brings significant code duplication and decreased composability (i.e. ability to mix-and-match libraries and toolkits). It's a hack that is rationalized post hoc.
[1] While Swift needs to support C, C++, and Objective-C interoperability, Apple's long-term goal is a predominately Swift-based ecosystem. And all of Apple's hardware is now 64-bit, so theoretically they could even support full C ABI interoperability without an undo memory hit by sparsely allocating stacks and extending them in-place on demand. Ultimately, I think part of the calculus is that it's easier to fiddle with your languages type system than it is to fix the low-level stack management of a pre-existing compiler (i.e. LLVM) to support many dynamic stacks. Go could do this because they wrote (or rewrote) their own compiler toolchain from scratch. Scheme and Lua can do this because the runtime VM stack is kept distinct from the native C ABI stack used by the engine; they effectively multiplex many VM stacks atop a single native C stack. Similar story for Java's Loom project regarding JVM stack management.
For TLS, examples of this core would be GSSAPI and the Java SSLEngine.
Also, SwiftTLS is not meant to be used in a production environment at this point. The disclaimer states: "It is not ready, has certainly a lot of bugs and received virtually no real world testing yet."
I hope I'm understanding your comment correctly.
I agree that once Rust lands async/await and it matures, it could be the go-to for safe, cross-platform libraries. That's my hope, too. I'm selfishly a Rust evangelist.
On Android the interop story is Java and on the Web it is going to be either JavaScript or WebAssembly.
Well, they're not really for production, are they?
For production, shouldn't we all be using the fastest, best-tested implementation, presumably in either C or assembly?