The Future of Reflective Programming in Swift

This seems like the best mechanism for me to try. I don't need the full power of the reflection API, just a subset of whatever S4TF needs to access. Since everything is JIT-compiled in my major use cases, depending on a small custom code base will speed up builds. Reading up on how you, @technogen, and others created your projects will be extremely helpful.

Still, this seems like a disproportionally large amount of time and effort on my side. Apple count just flip a boolean in their release toolchain's build script and all of this would be unnecessary. I guess I should at least be thankful that bypassing their restriction is possible in the first place. @Max_Desiatov can you approximate how many person-hours of elapsed time it took to create the custom reflection mechanism for Tokomak?

As I said, no custom reflection mechanism was created for Tokamak, we only reused an open-source library already available and that we already depended on. You'll have to get in touch with the library author to get an answer to your question.

Whenever I need a reflection mechanism powerful enough to enable the likes of SwiftUI.Environment (which I ended up completely reverse-engineering), I use the more powerful yet hidden reflection capabilities of Swift, which I made available by accessing the C functions from the Swift runtime and wrapping them in a more Swifty API:

I hope this helps!


In retrospect, I posted here without doing enough digging. Copying and pasting the contents of ReflectionMirror.swift is more than enough for my type introspection needs (I was just overwhelmed and didn't realize it). Rather, what I struggled with was bypassing the fact that certain members of KeyPath are not API-public. I easily reconstructed _forEachField, but it's extremely difficult to synthesize _forEachFieldWithKeyPath because that takes the output of _forEachField and transforms it into key path objects. The solution I need isn't conceptually demanding, it's just tedious and unsafe. I have to call some built-in functions for allocating object memory, modify some stored properties that aren't API-public, and bit-cast that to a KeyPath. Then, reimplement KeyPathBuffer and RawKeyPathComponent using the same tactics.

So it's definitely not something Apple would approve of in any app that went on their iOS App Store. But it's very good news, because I now understand the solution is physically possible. @Palle it's been a long and difficult journey, but by the Swift 5.7 release (iOS 16), it should be possible to run Swift for TensorFlow on an iPhone (GPU only, no CPU support). Whether I finish the Metal backend that quickly is another story.


I stayed away from this path for my own projects, because as I went deeper into the reimplementation, I would stumble on more internal APIs. Perhaps it’s safe to reconstruct the key-path builder types due to the ABI-stable layout, however I’m not sure if the runtime functions you need to call to get basic metadata are also ABI stable.

I’m just suggesting that this is probably not a viable long-term strategy, but it should be fine for a prototype implementation. I’d be interested to see your implementation when finished; in which project are going to deploy this reflection API in?

As some internal code in Swift for TensorFlow. This is the only way I can get it to run on release toolchains. Once I create a Metal and OpenCL backend that can directly substitute TensorFlow's C API/X10, S4TF will build entirely through Swift Package Manager magic. It will also be possible to compile for iOS and tvOS, letting you use it on Swift Playgrounds for the iPad.

If my approach is platform specific and ABI-unstable, I could fall back to a second option. I would just reimplement a huge chunk of the Swift Stdlib, making a new type named KeyPath2 or something. Either way, whatever approach I take should be technically feasible.


Not yet tested on 32-bit platforms.

1 Like

It's happening.

Reflective programming is vital to that effort. I have a minor runtime crash, and the culprit is probably swift-reflection-mirror. Fixing that bug is high on my priority list.