Hello Swifters,
I maintain a binding to the Godot game engine, and my binding requires a system that can map a string name into a constructor [1].
Today, for this system to work, I keep a hash table like this:
let godotFrameworkCtors = [
"Sprite": Sprite.self,
"Node": Node.self
]
And then, I use it like this [2]
if let type = godotFrameworkCtors(name) {
let result = ctor.init(InitContext(handle: nativeHandle, origin: .godot))
return result
}
This works, but the problem is that I end up creating a dictionary with about a thousand types which is fine as a dynamic library to serve all users, but it is problematic for people that only need a handful of types (even my Godot port to the iPad only references about 100 different types directly), so we end up with one chubby 100 megabyte library - even when statically linked.
The best solution I have been able to find is to rely on two functions with a scary underscore, and I am afraid that if these are not suitable to be used in the AppStore, it would undermine the effort entirely. The most important one is _typeByName
, which would allow me to convert a mangled name into the type, which back in 2019 was described in these forums as being the solution to this very problem [3], but @Joe_Groff warned:
The Swift runtime supports getting any type by mangled name, using the
_typeByName
function in the standard library. (It's unofficial, though, so may be subject to change.)
Are there any other alternatives I might have missed to invoke a constructor dynamically given a class name, or would it be acceptable to rely on _typeByName
at this point in time?
I have been tracking this for a while in my repo Reducing the size of SwiftGodot for deployments: godotFrameworksCtor. · Issue #555 · migueldeicaza/SwiftGodot · GitHub and two things brought a sense of urgency to it. The first one is that as Godot starts to make inroads into iOS and folks need access to Swift APIs my bridge is not exactly suitable to people, as it provides everything anyone might want - but most people just need very few pieces and it is making SwiftGodot unsuitable for them (one solution in this direction is blocked on a SwiftPM problem [4], I have an ugly band-aid that I am rushing to a few gaming folks, but it is kind of a shit sandwich) and I just learned that the Rust folks make their system work like I would like mine to work, and they are able to link out the 96 megs out of the 100 meg junk.
If I could use the _typeByName
or something in that vein, I could get that junk out of the way.
Would love any guidance I can get on this.
Miguel
[1] Background: This is used when I need to surface in a function the most derived type of a native Godot object. For example, consider a signature that looks like this:
func getParentNode() -> Node
Where Node is a base class of a rich hierarchy, the return value could be a Label, or a Window, or a Sprite. The goal of my code is to find the most derived type, so that the user can then write code like this:
if let sprite = player.getParentNode() as? Sprite {
sprite.moveLeft()
}
[2] The complete version has additional stuff, here is the function:
[3] Why is it possible to get a class from a String but not a struct or enum?
[4] [Pitch] SwiftPM: Allow targets to depend on products in the same package - #40 by migueldeicaza