2021-07-26 12:00:00
Alpaca Preview: Native Swift with ASP.NET Core
I have pushed up nuget packages for a preview version (0.1.10) of SourceGear.Alpaca.Swift.SDK. Yes, I said "Alpaca" rather than "Llama". So I should probably explain...
What is Alpaca? (starting from Llama)
My Llama project has grown to have two major pieces:
A compiler that converts LLVM bitcode to .NET CIL, allowing other languages to be used for .NET development. This piece was my starting point.
A binding generator that creates glue code so that those other languages can interact with .NET libraries. This piece came along later.
Llama takes its name from the first of these two pieces, because it has been the core concept, and because that piece is LLVM-centric, and because the word "Llama" starts with two L's, and because naming things is hard, so I saw no reason to be more creative.
But I recently realized that the second piece could be used without the first. I should probably have figured this out sooner.
My "LLVM bitcode to CIL" approach results in a strange kind of code which has no common name.
It is code running on the CLR, so it's not really "native code".
- But it is also code that never deals with object references or GC, so it's not "managed code" either.
For the moment, let's just call it "purple code". Over time, I have noticed that, with respect to interop with the CLR, the rules for purple code are awfully similar to the rules for native code.
And the thing I only recently realized is that those rules are not merely "similar" -- they are exactly the same.
Which means those bindings could be independent of the core of Llama. Yes, they need to be hooked up in different ways, but aside from that, they can be used unchanged with either purple code or native code.
So maybe those bindings deserve a life of their own, an opportunity to explore their place in the world without LLVM-to-CIL stuff.
So the name I am giving to that second piece is "Alpaca".
What is Alpaca?
Alpaca refers to my exploration of "great interop between .NET and other language ecosystems".
What do I mean by "great interop"? For one thing, I'm talking about calling .NET libraries from the other languages. .NET has always had excellent native interop features like P/Invoke, but those features are mostly focused on calling languages like C from C#. I'm talking about the opposite direction.
What if I want to call .NET libraries from native code? What if I want to write my ASP.NET Core web service in Swift instead of C#? Alpaca is about libraries and tooling to make that kind of use case simpler.
Llama SDK vs Alpaca SDK
Earlier I spoke of my project having two major pieces, which I am now calling Llama and Alpaca. The "third piece", which is smaller but more visible, is an MSBuild project SDK that integrates things into the regular dotnet
tooling.
In my previous Llama blog entry I showed a simple ASP.NET Core sample written in Swift:
The Llama Swift project SDK makes things work for Swift like they do for C# or F#. There is a Program.swift
file and a whatever.swiftproj
file. You can do dotnet build
, or dotnet run
, and so on.
The Alpaca Swift project SDK provides the same user experience, but accomplished in a very different way. Whereas the Llama SDK is compiling the Swift code to CIL, the Alpaca SDK is compiling to a native shared library. Both SDKs then provide their respective scaffolding to hook up the bindings and run the program.
One of my former coworkers often said that "sometimes a software project is like a car which has been disassembled and its parts are scattered on the front lawn".
Conceptually, given an ASP.NET Core program in Swift, I could switch between Llama and Alpaca by changing only the .swiftproj
file and not the Swift code itself.
Right now, some parts of my car are sitting out in the grass, so I can't actually do this. But it should work.
Why did I choose the name "Alpaca"? Because Wikipedia says an alpaca "is similar to, and often confused with, the llama", and I figured this blog entry was going to be darn confusing.
Sample
Inspired by Ben Adams (and building on his attempt with Llama), the sample for this preview is a Swift--Alpaca implementation of the TechEmpower benchmarks (plaintext and json):
https://github.com/ericsink/FrameworkBenchmarks/tree/alpaca/frameworks/Swift/alpacaBrief summary of the early results: Swift--Alpaca--AspNetCore is Not Terribly Fast. It's maybe a little faster than Swift--Vapor, but neither is in the ballpark of C#--AspNetCore. I don't know yet how much of the blame goes to my bindings as opposed to Swift itself. I'm still digging...
Moving forward
I still describe all this stuff using terms like "side project" and "exploratory project". So I don't do formal planning, and I don't make commitments.
I have no plans to abandon the Llama side of things, but for now, Alpaca is where I have traction, so that's where my current focus is.
And I should also admit that Alpaca differs from Llama in two ways that I find myself thinking about:
I'm pretty sure that "great interop between .NET and other language ecosystems" is a category of things that folks actually need. In contrast, "converting LLVM bitcode to CIL" is cool and interesting, but so far I'm not sure that it solves anybody's problem.
- Alpaca is a lot simpler than Llama. I mean, it's still pretty complicated. For example, the inheritance rules for C# and Swift are not quite the same, so I've got lots of edge cases to deal with. But my implementation of LLVM bitcode to CIL is still very "proof of concept", and getting that tool and its support libraries from here to "reliable and performant" would still be a big effort.
Technical requirements for this preview
The last few preview releases of Llama have been Windows-only. This one only supports Linux. I'm using Ubuntu 20.04 with WSL 2 on Windows 10.
The Alpaca Swift SDK needs Swift 5.4. And .NET Core 6 preview 6.
If you want to try the TE benchmarks, you need Docker, but the dockerfile
will setup the other prerequisites for you.
So you should be able to clone my fork (of Ben's fork) and do this:
./tfb --mode verify --test alpaca ./tfb --mode benchmark --test alpaca
Enjoy!