What is currently preventing Swift from having dynamic/runtime class generation api, similar to what ObjectiveC has with `objc_allocateClassPair`?
In other words, if one were tasked with implementing such mechanism, what unforseen obstacles/challenges there might be?
The goal is to let users create runtime-only classes that would be able to inherit from swift classes and adopt swift protocols for use with existing swift code. Dynamic executable code generation is (of course) out of scope.
This already effectively exists since generic types' metatype pointers need to be dynamically allocated at runtime. See swift_allocateGenericClassMetadata() and its related functions in the Swift runtime.
However, before you go diving in too deep—perhaps what you want to do can be accomplished with Swift generics or with other abstractions such as closures?
There shouldn't be any fundamental limitations to doing so. The Swift runtime supports dynamically loading classes and protocols and creating them on the fly from the repl.
If you don’t mind, could you provide any pointers on how should I approach the implementation, please? I’d like to attempt to build a prototype before I pitch anything in Evolution
To create new classes and protocols, you primarily need to follow the layout that is used by the Swift compiler and runtime. If you're writing in C++, or able to use Swift-C++ interop, you should be able to use the definitions from the include/swift/ABI/* headers from the Swift compiler codebase as a baseline. If you want these classes and protocols to be dynamically discoverable, so that lookup features like _typeByName or as? Protocol casts work, you will also need to register your types and protocols with the Swift runtime lookup tables. You can do this with the runtime functions swift_registerProtocolConformances, swift_registerProtocols, and swift_registerTypeMetadataRecords.
One roadblock I’ve run into while thinking through this is how to identify methods within swift code in a way that’s compatible with the runtime – specifically for overriding superclass methods and providing protocol witnesses.
As I reckon, at the ABI/runtime level there’s no notion of a “method name” neither for dispatch or reflection, yet for subclassing and witnessing we need some stable way to refer to an existing requirement or override point. Here are some ideas I've come up with so far:
A. Key paths would seem like an obvious answer here, but we don’t have method key paths today. And even for properties, key paths seem to abstract away accessor details behind simple get/set – not sure how to make this work from the API point of view.
B. Getting something like an unbound method (Foo.bar yielding (Foo) -> (T) -> U) and pointer-matching it against the vtable could probably work, but feels more like a hack.
C. Creating a new compiler directive similar to #selector, but returning a ProtocolRequirement/MethodDescriptor pointer. This would require some work within the compiler itself, unfortunately.
So, my questions here are:
What should be the actual approach?
Is it reasonable to conclude that a class-creation library of this kind can’t be implemented purely as an external library, relying exclusively on ABI-stable parts of the runtime?
Is there anything I might be missing with this vision? I’d appreciate any pointers.